Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 17:26:08 +0000 (09:26 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 17:26:08 +0000 (09:26 -0800)
Pull hwmon updates from Guenter Roeck:

 - New drivers for MAX6697 and compatibles and for INA209.

 - Added support for IT8771E, IT8772E, MAX34460, MAX34461, MCP98244, and
   ADT7420 to existing drivers.

 - Added support for additional attributes to various drivers.

 - Replaced SENSORS_LIMIT with clamp_val; retire SENSORS_LIMIT;

 - Clean up PMBus code to reduce its size; clean up adt7410 driver.

 - A couple of minor bug fixes as well as documentation cleanup.

 - Out-of-tree change: Replace SENSORS_LIMIT with clamp_val in
   platform/x86/eeepc-laptop driver.

* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (32 commits)
  hwmon: (ntc_thermistor): Fix sparse warnings
  hwmon: (adt7410) Add device table entry for the adt7420
  hwmon: (adt7410) Use I2C_ADDRS helper macro
  hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
  hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
  hwmon: (adt7410) Clear unwanted bits in the config register
  hwmon: (jc42) Add support for MCP98244
  hwmon: (pmbus) Clean up for code size reduction
  hwmon: (pmbus/max34440) Add support for MAX34460 and MAX34461
  hwmon: (pmbus) Add support for word status register
  hwmon: (pmbus/zl6100) Add support for VMON/VDRV
  hwmon: (pmbus) Add function to clear sensor cache
  hwmon: (pmbus) Add support for additional voltage sensor
  hwmon: (pmbus) Use krealloc to allocate attribute memory
  hwmon: (pmbus) Simplify memory allocation for sensor attributes
  hwmon: (pmbus) Improve boolean handling
  hwmon: (pmbus) Simplify memory allocation for labels and booleans
  hwmon: (pmbus) Use dev variable to represent client->dev
  hwmon: (pmbus) Fix 'Macros with multiple statements' checkpatch error
  hwmon: (pmbus) Drop unnecessary error messages in probe error path
  ...

82 files changed:
Documentation/devicetree/bindings/i2c/ina209.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/max6697.txt [new file with mode: 0644]
Documentation/hwmon/coretemp
Documentation/hwmon/ina209 [new file with mode: 0644]
Documentation/hwmon/it87
Documentation/hwmon/jc42
Documentation/hwmon/lm73 [new file with mode: 0644]
Documentation/hwmon/max34440
Documentation/hwmon/max6697 [new file with mode: 0644]
Documentation/hwmon/sysfs-interface
Documentation/hwmon/zl6100
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ad7414.c
drivers/hwmon/adm1021.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1031.c
drivers/hwmon/adm9240.c
drivers/hwmon/ads7828.c
drivers/hwmon/adt7410.c
drivers/hwmon/adt7462.c
drivers/hwmon/adt7470.c
drivers/hwmon/adt7475.c
drivers/hwmon/amc6821.c
drivers/hwmon/asb100.c
drivers/hwmon/asc7621.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/emc2103.c
drivers/hwmon/emc6w201.c
drivers/hwmon/f71882fg.c
drivers/hwmon/f75375s.c
drivers/hwmon/fschmd.c
drivers/hwmon/g760a.c
drivers/hwmon/gl518sm.c
drivers/hwmon/gl520sm.c
drivers/hwmon/ina209.c [new file with mode: 0644]
drivers/hwmon/it87.c
drivers/hwmon/jc42.c
drivers/hwmon/lm63.c
drivers/hwmon/lm73.c
drivers/hwmon/lm75.h
drivers/hwmon/lm77.c
drivers/hwmon/lm78.c
drivers/hwmon/lm80.c
drivers/hwmon/lm85.c
drivers/hwmon/lm90.c
drivers/hwmon/lm93.c
drivers/hwmon/lm95245.c
drivers/hwmon/max16065.c
drivers/hwmon/max1668.c
drivers/hwmon/max6639.c
drivers/hwmon/max6642.c
drivers/hwmon/max6650.c
drivers/hwmon/max6697.c [new file with mode: 0644]
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/max34440.c
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/pmbus/zl6100.c
drivers/hwmon/sht15.c
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/smsc47m192.c
drivers/hwmon/thmc50.c
drivers/hwmon/tmp102.c
drivers/hwmon/tmp401.c
drivers/hwmon/via686a.c
drivers/hwmon/vt1211.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwmon/w83795.c
drivers/hwmon/w83l786ng.c
drivers/platform/x86/eeepc-laptop.c
include/linux/hwmon.h
include/linux/platform_data/max6697.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/i2c/ina209.txt b/Documentation/devicetree/bindings/i2c/ina209.txt
new file mode 100644 (file)
index 0000000..9dd2bee
--- /dev/null
@@ -0,0 +1,18 @@
+ina209 properties
+
+Required properties:
+- compatible: Must be "ti,ina209"
+- reg: I2C address
+
+Optional properties:
+
+- shunt-resistor
+       Shunt resistor value in micro-Ohm
+
+Example:
+
+temp-sensor@4c {
+       compatible = "ti,ina209";
+       reg = <0x4c>;
+       shunt-resistor = <5000>;
+};
diff --git a/Documentation/devicetree/bindings/i2c/max6697.txt b/Documentation/devicetree/bindings/i2c/max6697.txt
new file mode 100644 (file)
index 0000000..5f79399
--- /dev/null
@@ -0,0 +1,64 @@
+max6697 properties
+
+Required properties:
+- compatible:
+       Should be one of
+               maxim,max6581
+               maxim,max6602
+               maxim,max6622
+               maxim,max6636
+               maxim,max6689
+               maxim,max6693
+               maxim,max6694
+               maxim,max6697
+               maxim,max6698
+               maxim,max6699
+- reg: I2C address
+
+Optional properties:
+
+- smbus-timeout-disable
+       Set to disable SMBus timeout. If not specified, SMBus timeout will be
+       enabled.
+- extended-range-enable
+       Only valid for MAX6581. Set to enable extended temperature range.
+       Extended temperature will be disabled if not specified.
+- beta-compensation-enable
+       Only valid for MAX6693 and MX6694. Set to enable beta compensation on
+       remote temperature channel 1.
+       Beta compensation will be disabled if not specified.
+- alert-mask
+       Alert bit mask. Alert disabled for bits set.
+       Select bit 0 for local temperature, bit 1..7 for remote temperatures.
+       If not specified, alert will be enabled for all channels.
+- over-temperature-mask
+       Over-temperature bit mask. Over-temperature reporting disabled for
+       bits set.
+       Select bit 0 for local temperature, bit 1..7 for remote temperatures.
+       If not specified, over-temperature reporting will be enabled for all
+       channels.
+- resistance-cancellation
+       Boolean for all chips other than MAX6581. Set to enable resistance
+       cancellation on remote temperature channel 1.
+       For MAX6581, resistance cancellation enabled for all channels if
+       specified as boolean, otherwise as per bit mask specified.
+       Only supported for remote temperatures (bit 1..7).
+       If not specified, resistance cancellation will be disabled for all
+       channels.
+- transistor-ideality
+       For MAX6581 only. Two values; first is bit mask, second is ideality
+       select value as per MAX6581 data sheet. Select bit 1..7 for remote
+       channels.
+       Transistor ideality will be initialized to default (1.008) if not
+       specified.
+
+Example:
+
+temp-sensor@1a {
+       compatible = "maxim,max6697";
+       reg = <0x1a>;
+       smbus-timeout-disable;
+       resistance-cancellation;
+       alert-mask = <0x72>;
+       over-temperature-mask = <0x7f>;
+};
index 3374c085678d694e450dbbab29c94d7c928ddde9..fec5a9bf755fb33b201dba540e02b4475a33b4a7 100644 (file)
@@ -66,6 +66,7 @@ Process               Processor                                       TjMax(C)
                i5 3470T                                        91
 
 32nm           Core i3/i5/i7 Processors
+               i7 2600                                         98
                i7 660UM/640/620, 640LM/620, 620M, 610E         105
                i5 540UM/520/430, 540M/520/450/430              105
                i3 330E, 370M/350/330                           90 rPGA, 105 BGA
@@ -79,7 +80,10 @@ Process              Processor                                       TjMax(C)
                P4505/P4500                                     90
 
 32nm           Atom Processors
+               S1260/1220                                      95
+               S1240                                           102
                Z2460                                           90
+               Z2760                                           90
                D2700/2550/2500                                 100
                N2850/2800/2650/2600                            100
 
@@ -98,6 +102,7 @@ Process              Processor                                       TjMax(C)
 
 45nm           Atom Processors
                D525/510/425/410                                100
+               K525/510/425/410                                100
                Z670/650                                        90
                Z560/550/540/530P/530/520PT/520/515/510PT/510P  90
                Z510/500                                        90
@@ -107,7 +112,11 @@ Process            Processor                                       TjMax(C)
                330/230                                         125
                E680/660/640/620                                90
                E680T/660T/640T/620T                            110
+               E665C/645C                                      90
+               E665CT/645CT                                    110
                CE4170/4150/4110                                110
+               CE4200 series                                   unknown
+               CE5300 series                                   unknown
 
 45nm           Core2 Processors
                Solo ULV SU3500/3300                            100
diff --git a/Documentation/hwmon/ina209 b/Documentation/hwmon/ina209
new file mode 100644 (file)
index 0000000..672501d
--- /dev/null
@@ -0,0 +1,93 @@
+Kernel driver ina209
+=====================
+
+Supported chips:
+  * Burr-Brown / Texas Instruments INA209
+    Prefix: 'ina209'
+    Addresses scanned: -
+    Datasheet:
+        http://www.ti.com/lit/gpn/ina209
+
+Author: Paul Hays <Paul.Hays@cattail.ca>
+Author: Ira W. Snyder <iws@ovro.caltech.edu>
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The TI / Burr-Brown INA209 monitors voltage, current, and power on the high side
+of a D.C. power supply. It can perform measurements and calculations in the
+background to supply readings at any time. It includes a programmable
+calibration multiplier to scale the displayed current and power values.
+
+
+Sysfs entries
+-------------
+
+The INA209 chip is highly configurable both via hardwiring and via
+the I2C bus. See the datasheet for details.
+
+This tries to expose most monitoring features of the hardware via
+sysfs. It does not support every feature of this chip.
+
+
+in0_input              shunt voltage (mV)
+in0_input_highest      shunt voltage historical maximum reading (mV)
+in0_input_lowest       shunt voltage historical minimum reading (mV)
+in0_reset_history      reset shunt voltage history
+in0_max                        shunt voltage max alarm limit (mV)
+in0_min                        shunt voltage min alarm limit (mV)
+in0_crit_max           shunt voltage crit max alarm limit (mV)
+in0_crit_min           shunt voltage crit min alarm limit (mV)
+in0_max_alarm          shunt voltage max alarm limit exceeded
+in0_min_alarm          shunt voltage min alarm limit exceeded
+in0_crit_max_alarm     shunt voltage crit max alarm limit exceeded
+in0_crit_min_alarm     shunt voltage crit min alarm limit exceeded
+
+in1_input              bus voltage (mV)
+in1_input_highest      bus voltage historical maximum reading (mV)
+in1_input_lowest       bus voltage historical minimum reading (mV)
+in1_reset_history      reset bus voltage history
+in1_max                        bus voltage max alarm limit (mV)
+in1_min                        bus voltage min alarm limit (mV)
+in1_crit_max           bus voltage crit max alarm limit (mV)
+in1_crit_min           bus voltage crit min alarm limit (mV)
+in1_max_alarm          bus voltage max alarm limit exceeded
+in1_min_alarm          bus voltage min alarm limit exceeded
+in1_crit_max_alarm     bus voltage crit max alarm limit exceeded
+in1_crit_min_alarm     bus voltage crit min alarm limit exceeded
+
+power1_input           power measurement (uW)
+power1_input_highest   power historical maximum reading (uW)
+power1_reset_history   reset power history
+power1_max             power max alarm limit (uW)
+power1_crit            power crit alarm limit (uW)
+power1_max_alarm       power max alarm limit exceeded
+power1_crit_alarm      power crit alarm limit exceeded
+
+curr1_input            current measurement (mA)
+
+update_interval                data conversion time; affects number of samples used
+                       to average results for shunt and bus voltages.
+
+General Remarks
+---------------
+
+The power and current registers in this chip require that the calibration
+register is programmed correctly before they are used. Normally this is expected
+to be done in the BIOS. In the absence of BIOS programming, the shunt resistor
+voltage can be provided using platform data. The driver uses platform data from
+the ina2xx driver for this purpose. If calibration register data is not provided
+via platform data, the driver checks if the calibration register has been
+programmed (ie has a value not equal to zero). If so, this value is retained.
+Otherwise, a default value reflecting a shunt resistor value of 10 mOhm is
+programmed into the calibration register.
+
+
+Output Pins
+-----------
+
+Output pin programming is a board feature which depends on the BIOS. It is
+outside the scope of a hardware monitoring driver to enable or disable output
+pins.
index 8386aadc0a8214df209d49c1c325b630c8392c5c..c263740f0cba83b5c3f17e95ecae83326da06458 100644 (file)
@@ -30,6 +30,14 @@ Supported chips:
     Prefix: 'it8728'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
+  * IT8771E
+    Prefix: 'it8771'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
+  * IT8772E
+    Prefix: 'it8772'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * IT8782F
     Prefix: 'it8782'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -83,8 +91,8 @@ Description
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F,
-IT8783E/F, and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E,
+IT8782F, IT8783E/F, and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -118,8 +126,8 @@ The IT8726F is just bit enhanced IT8716F with additional hardware
 for AMD power sequencing. Therefore the chip will appear as IT8716F
 to userspace applications.
 
-The IT8728F is considered compatible with the IT8721F, until a datasheet
-becomes available (hopefully.)
+The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F,
+until a datasheet becomes available (hopefully.)
 
 Temperatures are measured in degrees Celsius. An alarm is triggered once
 when the Overtemperature Shutdown limit is crossed.
index 66ecb9fc82468c46232c2744af6012fd2707906c..1650771212382296f6a63b321fce6b322dcba27e 100644 (file)
@@ -17,12 +17,13 @@ Supported chips:
   * Maxim MAX6604
     Datasheets:
        http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
-  * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
+  * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP98244, MCP9843
     Datasheets:
        http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
+       http://ww1.microchip.com/downloads/en/DeviceDoc/22327A.pdf
   * NXP Semiconductors SE97, SE97B, SE98, SE98A
     Datasheets:
        http://www.nxp.com/documents/data_sheet/SE97.pdf
diff --git a/Documentation/hwmon/lm73 b/Documentation/hwmon/lm73
new file mode 100644 (file)
index 0000000..8af059d
--- /dev/null
@@ -0,0 +1,90 @@
+Kernel driver lm73
+==================
+
+Supported chips:
+  * Texas Instruments LM73
+    Prefix: 'lm73'
+    Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4c, 0x4d, and 0x4e
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/product/lm73
+
+Author: Guillaume Ligneul <guillaume.ligneul@gmail.com>
+Documentation: Chris Verges <kg4ysn@gmail.com>
+
+
+Description
+-----------
+
+The LM73 is a digital temperature sensor.  All temperature values are
+given in degrees Celsius.
+
+Measurement Resolution Support
+------------------------------
+
+The LM73 supports four resolutions, defined in terms of degrees C per
+LSB: 0.25, 0.125, 0.0625, and 0.3125.  Changing the resolution mode
+affects the conversion time of the LM73's analog-to-digital converter.
+From userspace, the desired resolution can be specified as a function of
+conversion time via the 'update_interval' sysfs attribute for the
+device.  This attribute will normalize ranges of input values to the
+maximum times defined for the resolution in the datasheet.
+
+    Resolution    Conv. Time    Input Range
+    (C/LSB)       (msec)        (msec)
+    --------------------------------------
+    0.25          14             0..14
+    0.125         28            15..28
+    0.0625        56            29..56
+    0.03125       112           57..infinity
+    --------------------------------------
+
+The following examples show how the 'update_interval' attribute can be
+used to change the conversion time:
+
+    $ echo 0 > update_interval
+    $ cat update_interval
+    14
+    $ cat temp1_input
+    24250
+
+    $ echo 22 > update_interval
+    $ cat update_interval
+    28
+    $ cat temp1_input
+    24125
+
+    $ echo 56 > update_interval
+    $ cat update_interval
+    56
+    $ cat temp1_input
+    24062
+
+    $ echo 85 > update_interval
+    $ cat update_interval
+    112
+    $ cat temp1_input
+    24031
+
+As shown here, the lm73 driver automatically adjusts any user input for
+'update_interval' via a step function.  Reading back the
+'update_interval' value after a write operation will confirm the
+conversion time actively in use.
+
+Mathematically, the resolution can be derived from the conversion time
+via the following function:
+
+   g(x) = 0.250 * [log(x/14) / log(2)]
+
+where 'x' is the output from 'update_interval' and 'g(x)' is the
+resolution in degrees C per LSB.
+
+Alarm Support
+-------------
+
+The LM73 features a simple over-temperature alarm mechanism.  This
+feature is exposed via the sysfs attributes.
+
+The attributes 'temp1_max_alarm' and 'temp1_min_alarm' are flags
+provided by the LM73 that indicate whether the measured temperature has
+passed the 'temp1_max' and 'temp1_min' thresholds, respectively.  These
+values _must_ be read to clear the registers on the LM73.
index 04482226db208698564ef281de08ff31b883dd97..47651ff341aed4cc7ad95d20c052c57250e5c827 100644 (file)
@@ -16,6 +16,16 @@ Supported chips:
     Prefixes: 'max34446'
     Addresses scanned: -
     Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf
+  * Maxim MAX34460
+    PMBus 12-Channel Voltage Monitor & Sequencer
+    Prefix: 'max34460'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34460.pdf
+  * Maxim MAX34461
+    PMBus 16-Channel Voltage Monitor & Sequencer
+    Prefix: 'max34461'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34461.pdf
 
 Author: Guenter Roeck <guenter.roeck@ericsson.com>
 
@@ -26,6 +36,9 @@ Description
 This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel
 Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager
 and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger.
+It also supports the MAX34460 and MAX34461 PMBus Voltage Monitor & Sequencers.
+The MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
+channels.
 
 The driver is a client driver to the core PMBus driver. Please see
 Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -109,3 +122,6 @@ temp[1-8]_reset_history     Write any value to reset history.
 
                        temp7 and temp8 attributes only exist for MAX34440.
                        MAX34446 only supports temp[1-3].
+
+MAX34460 supports attribute groups in[1-12] and temp[1-5].
+MAX34461 supports attribute groups in[1-16] and temp[1-5].
diff --git a/Documentation/hwmon/max6697 b/Documentation/hwmon/max6697
new file mode 100644 (file)
index 0000000..6594177
--- /dev/null
@@ -0,0 +1,58 @@
+Kernel driver max6697
+=====================
+
+Supported chips:
+  * Maxim MAX6581
+    Prefix: 'max6581'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6581.pdf
+  * Maxim MAX6602
+    Prefix: 'max6602'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6602.pdf
+  * Maxim MAX6622
+    Prefix: 'max6622'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6622.pdf
+  * Maxim MAX6636
+    Prefix: 'max6636'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6636.pdf
+  * Maxim MAX6689
+    Prefix: 'max6689'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6689.pdf
+  * Maxim MAX6693
+    Prefix: 'max6693'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6693.pdf
+  * Maxim MAX6694
+    Prefix: 'max6694'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6694.pdf
+  * Maxim MAX6697
+    Prefix: 'max6697'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6697.pdf
+  * Maxim MAX6698
+    Prefix: 'max6698'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6698.pdf
+  * Maxim MAX6699
+    Prefix: 'max6699'
+    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6699.pdf
+
+Author:
+    Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for several MAX6697 compatible temperature sensor
+chips. The chips support one local temperature sensor plus four, six, or seven
+remote temperature sensors. Remote temperature sensors are diode-connected
+thermal transitors, except for MAX6698 which supports three diode-connected
+thermal transistors plus three thermistors in addition to the local temperature
+sensor.
+
+The driver provides the following sysfs attributes. temp1 is the local (chip)
+temperature, temp[2..n] are remote temperatures. The actually supported
+per-channel attributes are chip type and channel dependent.
+
+tempX_input      RO temperature
+tempX_max        RW temperature maximum threshold
+tempX_max_alarm  RO temperature maximum threshold alarm
+tempX_crit       RW temperature critical threshold
+tempX_crit_alarm RO temperature critical threshold alarm
+tempX_fault      RO temperature diode fault (remote sensors only)
index 1f4dd855a299350ec707fc9ec34630baef29c689..79f8257dd790703f8a9285e7b498f585df87e97b 100644 (file)
@@ -722,14 +722,14 @@ add/subtract if it has been divided before the add/subtract.
 What to do if a value is found to be invalid, depends on the type of the
 sysfs attribute that is being set. If it is a continuous setting like a
 tempX_max or inX_max attribute, then the value should be clamped to its
-limits using SENSORS_LIMIT(value, min_limit, max_limit). If it is not
-continuous like for example a tempX_type, then when an invalid value is
-written, -EINVAL should be returned.
+limits using clamp_val(value, min_limit, max_limit). If it is not continuous
+like for example a tempX_type, then when an invalid value is written,
+-EINVAL should be returned.
 
 Example1, temp1_max, register is a signed 8 bit value (-128 - 127 degrees):
 
        long v = simple_strtol(buf, NULL, 10) / 1000;
-       v = SENSORS_LIMIT(v, -128, 127);
+       v = clamp_val(v, -128, 127);
        /* write v to register */
 
 Example2, fan divider setting, valid values 2, 4 and 8:
index a995b41724fd8e98bf4b3b1eceacf6e2a2146ab2..3d924b6b59e915ff043e933209d7d449b6f889ce 100644 (file)
@@ -121,12 +121,26 @@ in1_max_alarm             Input voltage high alarm.
 in1_lcrit_alarm                Input voltage critical low alarm.
 in1_crit_alarm         Input voltage critical high alarm.
 
-in2_label              "vout1"
-in2_input              Measured output voltage.
-in2_lcrit              Critical minimum output Voltage.
-in2_crit               Critical maximum output voltage.
-in2_lcrit_alarm                Critical output voltage critical low alarm.
-in2_crit_alarm         Critical output voltage critical high alarm.
+in2_label              "vmon"
+in2_input              Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
+                       ZL9117M) pin. Reported voltage is 16x the voltage on the
+                       pin (adjusted internally by the chip).
+in2_lcrit              Critical minumum VMON/VDRV Voltage.
+in2_crit               Critical maximum VMON/VDRV voltage.
+in2_lcrit_alarm                VMON/VDRV voltage critical low alarm.
+in2_crit_alarm         VMON/VDRV voltage critical high alarm.
+
+                       vmon attributes are supported on ZL2004, ZL9101M,
+                       and ZL9117M only.
+
+inX_label              "vout1"
+inX_input              Measured output voltage.
+inX_lcrit              Critical minimum output Voltage.
+inX_crit               Critical maximum output voltage.
+inX_lcrit_alarm                Critical output voltage critical low alarm.
+inX_crit_alarm         Critical output voltage critical high alarm.
+
+                       X is 3 for ZL2004, ZL9101M, and ZL9117M, 2 otherwise.
 
 curr1_label            "iout1"
 curr1_input            Measured output current.
index 32f238f3caea852ad116fa9eab465c945fa0d6e3..89ac1cb26f24e6649b40ec253436bc4ee96437a5 100644 (file)
@@ -180,11 +180,11 @@ config SENSORS_ADM9240
          will be called adm9240.
 
 config SENSORS_ADT7410
-       tristate "Analog Devices ADT7410"
+       tristate "Analog Devices ADT7410/ADT7420"
        depends on I2C
        help
          If you say yes here you get support for the Analog Devices
-         ADT7410 temperature monitoring chip.
+         ADT7410 and ADT7420 temperature monitoring chips.
 
          This driver can also be built as a module. If so, the module
          will be called adt7410.
@@ -506,7 +506,8 @@ config SENSORS_IT87
        help
          If you say yes here you get support for ITE IT8705F, IT8712F,
          IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
-         IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
+         IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the
+         SiS950 clone.
 
          This driver can also be built as a module.  If so, the module
          will be called it87.
@@ -529,8 +530,8 @@ config SENSORS_JC42
          temperature sensors, which are used on many DDR3 memory modules for
          mobile devices and servers.  Support will include, but not be limited
          to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
-         MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002,
-         STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
+         MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E),
+         STTS2002, STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
 
          This driver can also be built as a module.  If so, the module
          will be called jc42.
@@ -854,6 +855,17 @@ config SENSORS_MAX6650
          This driver can also be built as a module.  If so, the module
          will be called max6650.
 
+config SENSORS_MAX6697
+       tristate "Maxim MAX6697 and compatibles"
+       depends on I2C
+       help
+         If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+         MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+         temperature sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max6697.
+
 config SENSORS_MCP3021
        tristate "Microchip MCP3021 and compatibles"
        depends on I2C
@@ -1145,6 +1157,16 @@ config SENSORS_AMC6821
          This driver can also be build as a module.  If so, the module
          will be called amc6821.
 
+config SENSORS_INA209
+       tristate "TI / Burr Brown INA209"
+       depends on I2C
+       help
+         If you say yes here you get support for the TI / Burr Brown INA209
+         voltage / current / power monitor I2C interface.
+
+         This driver can also be built as a module. If so, the module will
+         be called ina209.
+
 config SENSORS_INA2XX
        tristate "Texas Instruments INA219 and compatibles"
        depends on I2C
index 5da287443f6c3d007ae96b4e7a9d5d912fe3d3d7..8d6d97ea7c1e3d9e161f425cb236c79fce18c295 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
+obj-$(CONFIG_SENSORS_INA209)   += ina209.o
 obj-$(CONFIG_SENSORS_INA2XX)   += ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_JC42)     += jc42.o
@@ -99,6 +100,7 @@ obj-$(CONFIG_SENSORS_MAX197) += max197.o
 obj-$(CONFIG_SENSORS_MAX6639)  += max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)  += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
+obj-$(CONFIG_SENSORS_MAX6697)  += max6697.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)  += mcp3021.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
index f3a5d4764eb95be740066d7aaf94ea2a5db3c0a2..5d501adc3e54b3c477ffe125319e6473bdf10467 100644 (file)
@@ -137,7 +137,7 @@ static ssize_t set_max_min(struct device *dev,
        if (ret < 0)
                return ret;
 
-       temp = SENSORS_LIMIT(temp, -40000, 85000);
+       temp = clamp_val(temp, -40000, 85000);
        temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
 
        mutex_lock(&data->lock);
index fd1d1b15854ee6bedfab249ff31c0036b57a789a..71bcba8abfc0a927ffe88403ea2d2ce3339913d7 100644 (file)
@@ -193,7 +193,7 @@ static ssize_t set_temp_max(struct device *dev,
        temp /= 1000;
 
        mutex_lock(&data->update_lock);
-       data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+       data->temp_max[index] = clamp_val(temp, -128, 127);
        if (!read_only)
                i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
                                          data->temp_max[index]);
@@ -218,7 +218,7 @@ static ssize_t set_temp_min(struct device *dev,
        temp /= 1000;
 
        mutex_lock(&data->update_lock);
-       data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+       data->temp_min[index] = clamp_val(temp, -128, 127);
        if (!read_only)
                i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
                                          data->temp_min[index]);
index 0f068e7297ee10c8c2e8ab11b5fbc1eefb32fe32..ea09046e651d19d8585bb26b07bc7ba2339f9e3d 100644 (file)
@@ -197,7 +197,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
        };
 #define NEG12_OFFSET  16000
 #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n, val)  (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\
+#define INS_TO_REG(n, val)  (clamp_val(SCALE(val, adm1026_scaling[n], 192),\
        0, 255))
 #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
 
@@ -207,7 +207,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
  *      22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
  */
 #define FAN_TO_REG(val, div)  ((val) <= 0 ? 0xff : \
-                               SENSORS_LIMIT(1350000 / ((val) * (div)), \
+                               clamp_val(1350000 / ((val) * (div)), \
                                              1, 254))
 #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
                                1350000 / ((val) * (div)))
@@ -215,14 +215,14 @@ static int adm1026_scaling[] = { /* .001 Volts */
 #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
 
 /* Temperature is reported in 1 degC increments */
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
                                        / 1000, -127, 127))
 #define TEMP_FROM_REG(val) ((val) * 1000)
-#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
                                          / 1000, -127, 127))
 #define OFFSET_FROM_REG(val) ((val) * 1000)
 
-#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255))
+#define PWM_TO_REG(val) (clamp_val(val, 0, 255))
 #define PWM_FROM_REG(val) (val)
 
 #define PWM_MIN_TO_REG(val) ((val) & 0xf0)
@@ -233,7 +233,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
  *   indicates that the DAC could be used to drive the fans, but in our
  *   example board (Arima HDAMA) it isn't connected to the fans at all.
  */
-#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255))
+#define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255))
 #define DAC_FROM_REG(val) (((val) * 2500) / 255)
 
 /*
@@ -933,7 +933,7 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div)
                return;
 
        new_min = data->fan_min[fan] * old_div / new_div;
-       new_min = SENSORS_LIMIT(new_min, 1, 254);
+       new_min = clamp_val(new_min, 1, 254);
        data->fan_min[fan] = new_min;
        adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
 }
@@ -1527,7 +1527,7 @@ static ssize_t set_auto_pwm_min(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255);
+       data->pwm1.auto_pwm_min = clamp_val(val, 0, 255);
        if (data->pwm1.enable == 2) { /* apply immediately */
                data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
                        PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
index c6a4631e833f78a1143fa7b81ad1bc8f8b237d6f..253ea396106db45e18ae6b1a54022029d5b7afc9 100644 (file)
@@ -162,13 +162,13 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
 static int FAN_TO_REG(int reg, int div)
 {
        int tmp;
-       tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div);
+       tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
        return tmp > 255 ? 255 : tmp;
 }
 
 #define FAN_DIV_FROM_REG(reg)          (1<<(((reg)&0xc0)>>6))
 
-#define PWM_TO_REG(val)                        (SENSORS_LIMIT((val), 0, 255) >> 4)
+#define PWM_TO_REG(val)                        (clamp_val((val), 0, 255) >> 4)
 #define PWM_FROM_REG(val)              ((val) << 4)
 
 #define FAN_CHAN_FROM_REG(reg)         (((reg) >> 5) & 7)
@@ -675,7 +675,7 @@ static ssize_t set_temp_offset(struct device *dev,
        if (ret)
                return ret;
 
-       val = SENSORS_LIMIT(val, -15000, 15000);
+       val = clamp_val(val, -15000, 15000);
        mutex_lock(&data->update_lock);
        data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
        adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
@@ -696,7 +696,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
-       val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+       val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_min[nr] = TEMP_TO_REG(val);
        adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
@@ -717,7 +717,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
-       val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+       val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_max[nr] = TEMP_TO_REG(val);
        adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
@@ -738,7 +738,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
-       val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+       val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_crit[nr] = TEMP_TO_REG(val);
        adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
index dafa477715e327fcb324c86e51dba46e1afeb450..2416628e0ab1d78a264a4c8bc6a606a0057ed3fb 100644 (file)
@@ -98,13 +98,13 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n)
 
 static inline u8 IN_TO_REG(unsigned long val, int n)
 {
-       return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+       return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
 }
 
 /* temperature range: -40..125, 127 disables temperature alarm */
 static inline s8 TEMP_TO_REG(long val)
 {
-       return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
+       return clamp_val(SCALE(val, 1, 1000), -40, 127);
 }
 
 /* two fans, each with low fan speed limit */
@@ -122,7 +122,7 @@ static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
 /* analog out 0..1250mV */
 static inline u8 AOUT_TO_REG(unsigned long val)
 {
-       return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
+       return clamp_val(SCALE(val, 255, 1250), 0, 255);
 }
 
 static inline unsigned int AOUT_FROM_REG(u8 reg)
index 409b5c16defb1c0169c3871695c3b7b7c3d08fc0..ba962ac4b81f2e63519ee12138e1b2e298befe90 100644 (file)
@@ -163,9 +163,9 @@ static int ads7828_probe(struct i2c_client *client,
 
        /* Bound Vref with min/max values if it was provided */
        if (data->vref_mv)
-               data->vref_mv = SENSORS_LIMIT(data->vref_mv,
-                                             ADS7828_EXT_VREF_MV_MIN,
-                                             ADS7828_EXT_VREF_MV_MAX);
+               data->vref_mv = clamp_val(data->vref_mv,
+                                         ADS7828_EXT_VREF_MV_MIN,
+                                         ADS7828_EXT_VREF_MV_MAX);
        else
                data->vref_mv = ADS7828_INT_VREF_MV;
 
index 030c8d7c33a57b8f03463c4fbb220e5daf81b5d9..99a7290da0a343c4e0e970c57eebfeca86486589 100644 (file)
@@ -78,10 +78,6 @@ enum adt7410_type {          /* keep sorted in alphabetical order */
        adt7410,
 };
 
-/* Addresses scanned */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-                                       I2C_CLIENT_END };
-
 static const u8 ADT7410_REG_TEMP[4] = {
        ADT7410_TEMPERATURE,            /* input */
        ADT7410_T_ALARM_HIGH,           /* high */
@@ -173,8 +169,8 @@ abort:
 
 static s16 ADT7410_TEMP_TO_REG(long temp)
 {
-       return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
-                                              ADT7410_TEMP_MAX) * 128, 1000);
+       return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
+                                          ADT7410_TEMP_MAX) * 128, 1000);
 }
 
 static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
@@ -269,9 +265,9 @@ static ssize_t adt7410_set_t_hyst(struct device *dev,
                return ret;
        /* convert absolute hysteresis value to a 4 bit delta value */
        limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
-       hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
-       data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
-                                  0, ADT7410_T_HYST_MASK);
+       hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+       data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
+                              ADT7410_T_HYST_MASK);
        ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
        if (ret)
                return ret;
@@ -364,6 +360,7 @@ static int adt7410_probe(struct i2c_client *client,
        /*
         * Set to 16 bit resolution, continous conversion and comparator mode.
         */
+       ret &= ~ADT7410_MODE_MASK;
        data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
                        ADT7410_EVENT_MODE;
        if (data->config != data->oldconfig) {
@@ -410,11 +407,12 @@ static int adt7410_remove(struct i2c_client *client)
 
 static const struct i2c_device_id adt7410_ids[] = {
        { "adt7410", adt7410, },
+       { "adt7420", adt7410, },
        { /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int adt7410_suspend(struct device *dev)
 {
        int ret;
@@ -436,10 +434,8 @@ static int adt7410_resume(struct device *dev)
        return ret;
 }
 
-static const struct dev_pm_ops adt7410_dev_pm_ops = {
-       .suspend        = adt7410_suspend,
-       .resume         = adt7410_resume,
-};
+static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+
 #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
 #else
 #define ADT7410_DEV_PM_OPS NULL
@@ -454,11 +450,11 @@ static struct i2c_driver adt7410_driver = {
        .probe          = adt7410_probe,
        .remove         = adt7410_remove,
        .id_table       = adt7410_ids,
-       .address_list   = normal_i2c,
+       .address_list   = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
 
 module_i2c_driver(adt7410_driver);
 
 MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
 MODULE_LICENSE("GPL");
index 98a7d81e25c5f18de577c31db321481c0b0d225d..69481d3a3d231fec48e1f43f0489e20879613daf 100644 (file)
@@ -836,7 +836,7 @@ static ssize_t set_temp_min(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_min[attr->index] = temp;
@@ -874,7 +874,7 @@ static ssize_t set_temp_max(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_max[attr->index] = temp;
@@ -939,7 +939,7 @@ static ssize_t set_volt_max(struct device *dev,
 
        temp *= 1000; /* convert mV to uV */
        temp = DIV_ROUND_CLOSEST(temp, x);
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->volt_max[attr->index] = temp;
@@ -981,7 +981,7 @@ static ssize_t set_volt_min(struct device *dev,
 
        temp *= 1000; /* convert mV to uV */
        temp = DIV_ROUND_CLOSEST(temp, x);
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->volt_min[attr->index] = temp;
@@ -1071,7 +1071,7 @@ static ssize_t set_fan_min(struct device *dev,
 
        temp = FAN_RPM_TO_PERIOD(temp);
        temp >>= 8;
-       temp = SENSORS_LIMIT(temp, 1, 255);
+       temp = clamp_val(temp, 1, 255);
 
        mutex_lock(&data->lock);
        data->fan_min[attr->index] = temp;
@@ -1149,7 +1149,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm[attr->index] = temp;
@@ -1179,7 +1179,7 @@ static ssize_t set_pwm_max(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_max = temp;
@@ -1211,7 +1211,7 @@ static ssize_t set_pwm_min(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_min[attr->index] = temp;
@@ -1246,7 +1246,7 @@ static ssize_t set_pwm_hyst(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000);
-       temp = SENSORS_LIMIT(temp, 0, 15);
+       temp = clamp_val(temp, 0, 15);
 
        /* package things up */
        temp &= ADT7462_PWM_HYST_MASK;
@@ -1333,7 +1333,7 @@ static ssize_t set_pwm_tmin(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_tmin[attr->index] = temp;
index 39ecb1a3b9ef61982b0e81e9fbac5585da35dfac..b83bf4bb95eba3489e861d7f2d51e24e6a42d15f 100644 (file)
@@ -452,7 +452,7 @@ static ssize_t set_auto_update_interval(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 60000);
+       temp = clamp_val(temp, 0, 60000);
 
        mutex_lock(&data->lock);
        data->auto_update_interval = temp;
@@ -481,7 +481,7 @@ static ssize_t set_num_temp_sensors(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, -1, 10);
+       temp = clamp_val(temp, -1, 10);
 
        mutex_lock(&data->lock);
        data->num_temp_sensors = temp;
@@ -515,7 +515,7 @@ static ssize_t set_temp_min(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000);
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_min[attr->index] = temp;
@@ -549,7 +549,7 @@ static ssize_t set_temp_max(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000);
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_max[attr->index] = temp;
@@ -604,7 +604,7 @@ static ssize_t set_fan_max(struct device *dev,
                return -EINVAL;
 
        temp = FAN_RPM_TO_PERIOD(temp);
-       temp = SENSORS_LIMIT(temp, 1, 65534);
+       temp = clamp_val(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_max[attr->index] = temp;
@@ -641,7 +641,7 @@ static ssize_t set_fan_min(struct device *dev,
                return -EINVAL;
 
        temp = FAN_RPM_TO_PERIOD(temp);
-       temp = SENSORS_LIMIT(temp, 1, 65534);
+       temp = clamp_val(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_min[attr->index] = temp;
@@ -717,7 +717,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm[attr->index] = temp;
@@ -749,7 +749,7 @@ static ssize_t set_pwm_max(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_max[attr->index] = temp;
@@ -782,7 +782,7 @@ static ssize_t set_pwm_min(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_min[attr->index] = temp;
@@ -826,7 +826,7 @@ static ssize_t set_pwm_tmin(struct device *dev,
                return -EINVAL;
 
        temp = DIV_ROUND_CLOSEST(temp, 1000);
-       temp = SENSORS_LIMIT(temp, 0, 255);
+       temp = clamp_val(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_tmin[attr->index] = temp;
index 989e54c3925224a84bbf8bc55ac900a53fdf49ad..22d008bbdc1011d16919e70170f2f9d09b394235 100644 (file)
@@ -201,10 +201,10 @@ static inline u16 temp2reg(struct adt7475_data *data, long val)
        u16 ret;
 
        if (!(data->config5 & CONFIG5_TWOSCOMP)) {
-               val = SENSORS_LIMIT(val, -64000, 191000);
+               val = clamp_val(val, -64000, 191000);
                ret = (val + 64500) / 1000;
        } else {
-               val = SENSORS_LIMIT(val, -128000, 127000);
+               val = clamp_val(val, -128000, 127000);
                if (val < -500)
                        ret = (256500 + val) / 1000;
                else
@@ -240,7 +240,7 @@ static inline u16 rpm2tach(unsigned long rpm)
        if (rpm == 0)
                return 0;
 
-       return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF);
+       return clamp_val((90000 * 60) / rpm, 1, 0xFFFF);
 }
 
 /* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
@@ -271,7 +271,7 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn)
                reg = (volt * 1024) / 2250;
        else
                reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250);
-       return SENSORS_LIMIT(reg, 0, 1023) & (0xff << 2);
+       return clamp_val(reg, 0, 1023) & (0xff << 2);
 }
 
 static u16 adt7475_read_word(struct i2c_client *client, int reg)
@@ -451,10 +451,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
        switch (sattr->nr) {
        case OFFSET:
                if (data->config5 & CONFIG5_TEMPOFFSET) {
-                       val = SENSORS_LIMIT(val, -63000, 127000);
+                       val = clamp_val(val, -63000, 127000);
                        out = data->temp[OFFSET][sattr->index] = val / 1000;
                } else {
-                       val = SENSORS_LIMIT(val, -63000, 64000);
+                       val = clamp_val(val, -63000, 64000);
                        out = data->temp[OFFSET][sattr->index] = val / 500;
                }
                break;
@@ -471,7 +471,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
                adt7475_read_hystersis(client);
 
                temp = reg2temp(data, data->temp[THERM][sattr->index]);
-               val = SENSORS_LIMIT(val, temp - 15000, temp);
+               val = clamp_val(val, temp - 15000, temp);
                val = (temp - val) / 1000;
 
                if (sattr->index != 1) {
@@ -577,7 +577,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
         * to figure the range
         */
        temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
-       val = SENSORS_LIMIT(val, temp + autorange_table[0],
+       val = clamp_val(val, temp + autorange_table[0],
                temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
        val -= temp;
 
@@ -701,7 +701,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                break;
        }
 
-       data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF);
+       data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
        i2c_smbus_write_byte_data(client, reg,
                                  data->pwm[sattr->nr][sattr->index]);
 
index ae482e3afdac8c135eb3d501a6f20773a1624db5..4fe49d2bfe1de5c44b61b6bb3cbcfa3acecec41e 100644 (file)
@@ -241,7 +241,7 @@ static ssize_t set_temp(
        int ret = kstrtol(buf, 10, &val);
        if (ret)
                return ret;
-       val = SENSORS_LIMIT(val / 1000, -128, 127);
+       val = clamp_val(val / 1000, -128, 127);
 
        mutex_lock(&data->update_lock);
        data->temp[ix] = val;
@@ -332,7 +332,7 @@ static ssize_t set_pwm1(
                return ret;
 
        mutex_lock(&data->update_lock);
-       data->pwm1 = SENSORS_LIMIT(val , 0, 255);
+       data->pwm1 = clamp_val(val , 0, 255);
        i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1);
        mutex_unlock(&data->update_lock);
        return count;
@@ -499,11 +499,11 @@ static ssize_t set_temp_auto_point_temp(
        mutex_lock(&data->update_lock);
        switch (ix) {
        case 0:
-               ptemp[0] = SENSORS_LIMIT(val / 1000, 0,
-                               data->temp1_auto_point_temp[1]);
-               ptemp[0] = SENSORS_LIMIT(ptemp[0], 0,
-                               data->temp2_auto_point_temp[1]);
-               ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63);
+               ptemp[0] = clamp_val(val / 1000, 0,
+                                    data->temp1_auto_point_temp[1]);
+               ptemp[0] = clamp_val(ptemp[0], 0,
+                                    data->temp2_auto_point_temp[1]);
+               ptemp[0] = clamp_val(ptemp[0], 0, 63);
                if (i2c_smbus_write_byte_data(
                                        client,
                                        AMC6821_REG_PSV_TEMP,
@@ -515,20 +515,12 @@ static ssize_t set_temp_auto_point_temp(
                goto EXIT;
                break;
        case 1:
-               ptemp[1] = SENSORS_LIMIT(
-                                       val / 1000,
-                                       (ptemp[0] & 0x7C) + 4,
-                                       124);
+               ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
                ptemp[1] &= 0x7C;
-               ptemp[2] = SENSORS_LIMIT(
-                                       ptemp[2], ptemp[1] + 1,
-                                       255);
+               ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
                break;
        case 2:
-               ptemp[2] = SENSORS_LIMIT(
-                                       val / 1000,
-                                       ptemp[1]+1,
-                                       255);
+               ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255);
                break;
        default:
                dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
@@ -561,7 +553,7 @@ static ssize_t set_pwm1_auto_point_pwm(
                return ret;
 
        mutex_lock(&data->update_lock);
-       data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254);
+       data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
        if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP,
                        data->pwm1_auto_point_pwm[1])) {
                dev_err(&client->dev, "Register write error, aborting.\n");
@@ -629,7 +621,7 @@ static ssize_t set_fan(
        val = 1 > val ? 0xFFFF : 6000000/val;
 
        mutex_lock(&data->update_lock);
-       data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF);
+       data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF);
        if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
                        data->fan[ix] & 0xFF)) {
                dev_err(&client->dev, "Register write error, aborting.\n");
index 520e5bf4f76d9f8cd1b16edf5610554fde103181..6ac612cabda1e1acace7382c74a553346468097f 100644 (file)
@@ -114,7 +114,7 @@ static const u16 asb100_reg_temp_hyst[]     = {0, 0x3a, 0x153, 0x253, 0x19};
  */
 static u8 IN_TO_REG(unsigned val)
 {
-       unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
+       unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
        return (nval + 8) / 16;
 }
 
@@ -129,8 +129,8 @@ static u8 FAN_TO_REG(long rpm, int div)
                return 0;
        if (rpm == 0)
                return 255;
-       rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+       rpm = clamp_val(rpm, 1, 1000000);
+       return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static int FAN_FROM_REG(u8 val, int div)
@@ -148,7 +148,7 @@ static int FAN_FROM_REG(u8 val, int div)
  */
 static u8 TEMP_TO_REG(long temp)
 {
-       int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
+       int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
        ntemp += (ntemp < 0 ? -500 : 500);
        return (u8)(ntemp / 1000);
 }
@@ -164,7 +164,7 @@ static int TEMP_FROM_REG(u8 reg)
  */
 static u8 ASB100_PWM_TO_REG(int pwm)
 {
-       pwm = SENSORS_LIMIT(pwm, 0, 255);
+       pwm = clamp_val(pwm, 0, 255);
        return (u8)(pwm / 16);
 }
 
index b867aab7804975f91fc53f7cc76382f4af39694f..da7f5b5d5db5a2e36ca1295fc9052651f35ab0c2 100644 (file)
@@ -191,7 +191,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
        if (kstrtol(buf, 10, &reqval))
                return -EINVAL;
 
-       reqval = SENSORS_LIMIT(reqval, 0, 255);
+       reqval = clamp_val(reqval, 0, 255);
 
        mutex_lock(&data->update_lock);
        data->reg[param->msb[0]] = reqval;
@@ -224,7 +224,7 @@ static ssize_t store_bitmask(struct device *dev,
        if (kstrtol(buf, 10, &reqval))
                return -EINVAL;
 
-       reqval = SENSORS_LIMIT(reqval, 0, param->mask[0]);
+       reqval = clamp_val(reqval, 0, param->mask[0]);
 
        reqval = (reqval & param->mask[0]) << param->shift[0];
 
@@ -274,7 +274,7 @@ static ssize_t store_fan16(struct device *dev,
         * generating an alarm.
         */
        reqval =
-           (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe));
+           (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe));
 
        mutex_lock(&data->update_lock);
        data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
@@ -343,11 +343,11 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
        if (kstrtol(buf, 10, &reqval))
                return -EINVAL;
 
-       reqval = SENSORS_LIMIT(reqval, 0, 0xffff);
+       reqval = clamp_val(reqval, 0, 0xffff);
 
        reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
 
-       reqval = SENSORS_LIMIT(reqval, 0, 0xff);
+       reqval = clamp_val(reqval, 0, 0xff);
 
        mutex_lock(&data->update_lock);
        data->reg[param->msb[0]] = reqval;
@@ -376,7 +376,7 @@ static ssize_t store_temp8(struct device *dev,
        if (kstrtol(buf, 10, &reqval))
                return -EINVAL;
 
-       reqval = SENSORS_LIMIT(reqval, -127000, 127000);
+       reqval = clamp_val(reqval, -127000, 127000);
 
        temp = reqval / 1000;
 
@@ -432,7 +432,7 @@ static ssize_t store_temp62(struct device *dev,
        if (kstrtol(buf, 10, &reqval))
                return -EINVAL;
 
-       reqval = SENSORS_LIMIT(reqval, -32000, 31750);
+       reqval = clamp_val(reqval, -32000, 31750);
        i = reqval / 1000;
        f = reqval - (i * 1000);
        temp = i << 2;
@@ -468,7 +468,7 @@ static ssize_t show_ap2_temp(struct device *dev,
        auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
        regval =
            ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
-       temp = auto_point1 + asc7621_range_map[SENSORS_LIMIT(regval, 0, 15)];
+       temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)];
        mutex_unlock(&data->update_lock);
 
        return sprintf(buf, "%d\n", temp);
@@ -489,7 +489,7 @@ static ssize_t store_ap2_temp(struct device *dev,
 
        mutex_lock(&data->update_lock);
        auto_point1 = data->reg[param->msb[1]] * 1000;
-       reqval = SENSORS_LIMIT(reqval, auto_point1 + 2000, auto_point1 + 80000);
+       reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000);
 
        for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
                if (reqval >= auto_point1 + asc7621_range_map[i]) {
@@ -523,7 +523,7 @@ static ssize_t show_pwm_ac(struct device *dev,
        regval = config | (altbit << 3);
        mutex_unlock(&data->update_lock);
 
-       return sprintf(buf, "%u\n", map[SENSORS_LIMIT(regval, 0, 15)]);
+       return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]);
 }
 
 static ssize_t store_pwm_ac(struct device *dev,
@@ -663,7 +663,7 @@ static ssize_t show_pwm_freq(struct device *dev,
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
-       regval = SENSORS_LIMIT(regval, 0, 15);
+       regval = clamp_val(regval, 0, 15);
 
        return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
 }
@@ -711,7 +711,7 @@ static ssize_t show_pwm_ast(struct device *dev,
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
-       regval = SENSORS_LIMIT(regval, 0, 7);
+       regval = clamp_val(regval, 0, 7);
 
        return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
 
@@ -759,7 +759,7 @@ static ssize_t show_temp_st(struct device *dev,
        SETUP_SHOW_data_param(dev, attr);
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
-       regval = SENSORS_LIMIT(regval, 0, 7);
+       regval = clamp_val(regval, 0, 7);
 
        return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
 }
index d64923d6353741ba8a6e9c233712bd448849478c..3f1e297663ada0fefa412ce2e0fd4e362d84af50 100644 (file)
@@ -198,7 +198,7 @@ struct tjmax {
 static const struct tjmax __cpuinitconst tjmax_table[] = {
        { "CPU  230", 100000 },         /* Model 0x1c, stepping 2       */
        { "CPU  330", 125000 },         /* Model 0x1c, stepping 2       */
-       { "CPU CE4110", 110000 },       /* Model 0x1c, stepping 10      */
+       { "CPU CE4110", 110000 },       /* Model 0x1c, stepping 10 Sodaville */
        { "CPU CE4150", 110000 },       /* Model 0x1c, stepping 10      */
        { "CPU CE4170", 110000 },       /* Model 0x1c, stepping 10      */
 };
@@ -212,7 +212,7 @@ struct tjmax_model {
 #define ANY 0xff
 
 static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
-       { 0x1c, 10, 100000 },   /* D4xx, N4xx, D5xx, N5xx */
+       { 0x1c, 10, 100000 },   /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
        { 0x1c, ANY, 90000 },   /* Z5xx, N2xx, possibly others
                                 * Note: Also matches 230 and 330,
                                 * which are covered by tjmax_table
@@ -222,6 +222,7 @@ static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
                                 * is undetectable by software
                                 */
        { 0x27, ANY, 90000 },   /* Atom Medfield (Z2460) */
+       { 0x35, ANY, 90000 },   /* Atom Clover Trail/Cloverview (Z2760) */
        { 0x36, ANY, 100000 },  /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
 };
 
index 7430f70ae452958b5a1bdbd8be308fdbf5a2e405..c347c94f2f7336dbc4b86f3e841f7ebf1a44954b 100644 (file)
@@ -277,7 +277,7 @@ static inline int IN_FROM_REG(int reg, int nominal, int res)
 
 static inline int IN_TO_REG(int val, int nominal)
 {
-       return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
+       return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
 }
 
 /*
@@ -293,8 +293,7 @@ static inline int TEMP_FROM_REG(int reg, int res)
 
 static inline int TEMP_TO_REG(int val)
 {
-       return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
-                            -128, 127);
+       return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
 }
 
 /* Temperature range */
@@ -332,7 +331,7 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix)
 
 static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
 {
-       int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+       int hyst = clamp_val((val + 500) / 1000, 0, 15);
 
        return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
 }
@@ -349,10 +348,10 @@ static inline int FAN_FROM_REG(int reg, int tpc)
 static inline int FAN_TO_REG(int val, int tpc)
 {
        if (tpc) {
-               return SENSORS_LIMIT(val / tpc, 0, 0xffff);
+               return clamp_val(val / tpc, 0, 0xffff);
        } else {
                return (val <= 0) ? 0xffff :
-                       SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe);
+                       clamp_val(90000 * 60 / val, 0, 0xfffe);
        }
 }
 
@@ -1282,7 +1281,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        mutex_lock(&data->update_lock);
        switch (fn) {
        case SYS_PWM:
-               data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+               data->pwm[ix] = clamp_val(val, 0, 255);
                dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
                break;
        case SYS_PWM_FREQ:
@@ -1450,7 +1449,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                break;
        case SYS_PWM_AUTO_POINT1_PWM:
                /* Only valid for pwm[1-3] */
-               data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+               data->pwm_min[ix] = clamp_val(val, 0, 255);
                dme1737_write(data, DME1737_REG_PWM_MIN(ix),
                              data->pwm_min[ix]);
                break;
index 77f434c5823690930f0cfa0d2e41932d91eb3223..b073056220873d4e147150b4e376b0f9c40c363d 100644 (file)
@@ -405,7 +405,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
        if (rpm_target == 0)
                data->fan_target = 0x1fff;
        else
-               data->fan_target = SENSORS_LIMIT(
+               data->fan_target = clamp_val(
                        (FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
                        0, 0x1fff);
 
index 789bd4fb329b9b2eeca82b07751ab538b5c19e9a..936898f82f94d140ab00d0b58d78bc195d23e480 100644 (file)
@@ -220,7 +220,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
                          : EMC6W201_REG_IN_HIGH(nr);
 
        mutex_lock(&data->update_lock);
-       data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+       data->in[sf][nr] = clamp_val(val, 0, 255);
        err = emc6w201_write8(client, reg, data->in[sf][nr]);
        mutex_unlock(&data->update_lock);
 
@@ -257,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
                          : EMC6W201_REG_TEMP_HIGH(nr);
 
        mutex_lock(&data->update_lock);
-       data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+       data->temp[sf][nr] = clamp_val(val, -127, 128);
        err = emc6w201_write8(client, reg, data->temp[sf][nr]);
        mutex_unlock(&data->update_lock);
 
@@ -298,7 +298,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
                val = 0xFFFF;
        } else {
                val = DIV_ROUND_CLOSEST(5400000U, val);
-               val = SENSORS_LIMIT(val, 0, 0xFFFE);
+               val = clamp_val(val, 0, 0xFFFE);
        }
 
        mutex_lock(&data->update_lock);
index bb7275cc47f30d8055f871cf3904bfde33f862cb..cfb02dd91aadda144e5986e19e3f57e0fd65743e 100644 (file)
@@ -1350,7 +1350,7 @@ static ssize_t store_fan_full_speed(struct device *dev,
        if (err)
                return err;
 
-       val = SENSORS_LIMIT(val, 23, 1500000);
+       val = clamp_val(val, 23, 1500000);
        val = fan_to_reg(val);
 
        mutex_lock(&data->update_lock);
@@ -1438,7 +1438,7 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
                return err;
 
        val /= 8;
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
@@ -1542,7 +1542,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
                return err;
 
        val /= 1000;
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
@@ -1589,8 +1589,7 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
 
        /* convert abs to relative and check */
        data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
-       val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
-                           data->temp_high[nr]);
+       val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
        val = data->temp_high[nr] - val;
 
        /* convert value to register contents */
@@ -1627,7 +1626,7 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
                return err;
 
        val /= 1000;
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
@@ -1754,7 +1753,7 @@ static ssize_t store_pwm(struct device *dev,
        if (err)
                return err;
 
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1805,7 +1804,7 @@ static ssize_t store_simple_pwm(struct device *dev,
        if (err)
                return err;
 
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
@@ -1932,7 +1931,7 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
        if (err)
                return err;
 
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1991,8 +1990,8 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_temp[nr][point] =
                f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
-       val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
-                               data->pwm_auto_point_temp[nr][point]);
+       val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
+                       data->pwm_auto_point_temp[nr][point]);
        val = data->pwm_auto_point_temp[nr][point] - val;
 
        reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
@@ -2126,9 +2125,9 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
        val /= 1000;
 
        if (data->auto_point_temp_signed)
-               val = SENSORS_LIMIT(val, -128, 127);
+               val = clamp_val(val, -128, 127);
        else
-               val = SENSORS_LIMIT(val, 0, 127);
+               val = clamp_val(val, 0, 127);
 
        mutex_lock(&data->update_lock);
        f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
index f7dba229395f9a844da9a8418ac9c5b2918d75dd..9e300e567f15c6b0cc22d6245e9a1cccbc1d8e0e 100644 (file)
@@ -359,7 +359,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+       data->pwm[nr] = clamp_val(val, 0, 255);
        f75375_write_pwm(client, nr);
        mutex_unlock(&data->update_lock);
        return count;
@@ -556,7 +556,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
-       val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+       val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
        mutex_lock(&data->update_lock);
        data->in_max[nr] = val;
        f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
@@ -577,7 +577,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
-       val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+       val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
        mutex_lock(&data->update_lock);
        data->in_min[nr] = val;
        f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
@@ -625,7 +625,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
-       val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+       val = clamp_val(TEMP_TO_REG(val), 0, 127);
        mutex_lock(&data->update_lock);
        data->temp_high[nr] = val;
        f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
@@ -646,7 +646,7 @@ static ssize_t set_temp_max_hyst(struct device *dev,
        if (err < 0)
                return err;
 
-       val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+       val = clamp_val(TEMP_TO_REG(val), 0, 127);
        mutex_lock(&data->update_lock);
        data->temp_max_hyst[nr] = val;
        f75375_write8(client, F75375_REG_TEMP_HYST(nr),
@@ -822,7 +822,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
                if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
                    !duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
                        continue;
-               data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
+               data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255);
                f75375_write_pwm(client, nr);
        }
 
index 519ce8b9c1427af878d495cb89addf42b20db1ef..8af2755cdb871201fc56f6a0ab4ad149b21634c6 100644 (file)
@@ -379,7 +379,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
        if (err)
                return err;
 
-       v = SENSORS_LIMIT(v / 1000, -128, 127) + 128;
+       v = clamp_val(v / 1000, -128, 127) + 128;
 
        mutex_lock(&data->update_lock);
        i2c_smbus_write_byte_data(to_i2c_client(dev),
@@ -540,7 +540,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
 
        /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
        if (v || data->kind == fscsyl) {
-               v = SENSORS_LIMIT(v, 128, 255);
+               v = clamp_val(v, 128, 255);
                v = (v - 128) * 2 + 1;
        }
 
index 8b2106f60edac7e91c4eb6eaabfb2cc6585636a0..ea6480b80e7fcd3df07eb80c91a52e9620b9019f 100644 (file)
@@ -171,7 +171,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       data->set_cnt = PWM_TO_CNT(SENSORS_LIMIT(val, 0, 255));
+       data->set_cnt = PWM_TO_CNT(clamp_val(val, 0, 255));
        g760a_write_value(client, G760A_REG_SET_CNT, data->set_cnt);
        mutex_unlock(&data->update_lock);
 
index 2c74673f48e5b770caa5478191c0574310d038ab..e2e5909a34df05fba91e7ac71f33905b9d0d91c0 100644 (file)
@@ -86,7 +86,7 @@ enum chips { gl518sm_r00, gl518sm_r80 };
 #define BOOL_FROM_REG(val)     ((val) ? 0 : 1)
 #define BOOL_TO_REG(val)       ((val) ? 0 : 1)
 
-#define TEMP_TO_REG(val)       SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val)       clamp_val(((((val) < 0 ? \
                                (val) - 500 : \
                                (val) + 500) / 1000) + 119), 0, 255)
 #define TEMP_FROM_REG(val)     (((val) - 119) * 1000)
@@ -96,15 +96,15 @@ static inline u8 FAN_TO_REG(long rpm, int div)
        long rpmdiv;
        if (rpm == 0)
                return 0;
-       rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div;
-       return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
+       rpmdiv = clamp_val(rpm, 1, 960000) * div;
+       return clamp_val((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
 }
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div))))
 
-#define IN_TO_REG(val)         SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val)         clamp_val((((val) + 9) / 19), 0, 255)
 #define IN_FROM_REG(val)       ((val) * 19)
 
-#define VDD_TO_REG(val)                SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val)                clamp_val((((val) * 4 + 47) / 95), 0, 255)
 #define VDD_FROM_REG(val)      (((val) * 95 + 2) / 4)
 
 #define DIV_FROM_REG(val)      (1 << (val))
index a21ff252f2f1b8cd6a14a898bf72fd36f9ce3465..ed56e09c3dd7147b4f209fb0a79244300692c341 100644 (file)
@@ -144,10 +144,10 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
 
 #define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
-#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255)
 
 #define IN_FROM_REG(val) ((val) * 19)
-#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255)
 
 static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
                            char *buf)
@@ -285,8 +285,7 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
 #define DIV_FROM_REG(val) (1 << (val))
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
 #define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \
-       SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \
-                     255))
+       clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
 
 static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
                             char *buf)
@@ -450,7 +449,7 @@ static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
                get_fan_off, set_fan_off);
 
 #define TEMP_FROM_REG(val) (((val) - 130) * 1000)
-#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \
                        (val) - 500 : (val) + 500) / 1000) + 130), 0, 255)
 
 static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
new file mode 100644 (file)
index 0000000..c6fdd5b
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Driver for the Texas Instruments / Burr Brown INA209
+ * Bidirectional Current/Power Monitor
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from Ira W. Snyder's original driver submission
+ *     Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca>
+ *     Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Aligned with ina2xx driver
+ *     Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ *     Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.ti.com/lit/gpn/ina209
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* register definitions */
+#define INA209_CONFIGURATION           0x00
+#define INA209_STATUS                  0x01
+#define INA209_STATUS_MASK             0x02
+#define INA209_SHUNT_VOLTAGE           0x03
+#define INA209_BUS_VOLTAGE             0x04
+#define INA209_POWER                   0x05
+#define INA209_CURRENT                 0x06
+#define INA209_SHUNT_VOLTAGE_POS_PEAK  0x07
+#define INA209_SHUNT_VOLTAGE_NEG_PEAK  0x08
+#define INA209_BUS_VOLTAGE_MAX_PEAK    0x09
+#define INA209_BUS_VOLTAGE_MIN_PEAK    0x0a
+#define INA209_POWER_PEAK              0x0b
+#define INA209_SHUNT_VOLTAGE_POS_WARN  0x0c
+#define INA209_SHUNT_VOLTAGE_NEG_WARN  0x0d
+#define INA209_POWER_WARN              0x0e
+#define INA209_BUS_VOLTAGE_OVER_WARN   0x0f
+#define INA209_BUS_VOLTAGE_UNDER_WARN  0x10
+#define INA209_POWER_OVER_LIMIT                0x11
+#define INA209_BUS_VOLTAGE_OVER_LIMIT  0x12
+#define INA209_BUS_VOLTAGE_UNDER_LIMIT 0x13
+#define INA209_CRITICAL_DAC_POS                0x14
+#define INA209_CRITICAL_DAC_NEG                0x15
+#define INA209_CALIBRATION             0x16
+
+#define INA209_REGISTERS               0x17
+
+#define INA209_CONFIG_DEFAULT          0x3c47  /* PGA=8, full range */
+#define INA209_SHUNT_DEFAULT           10000   /* uOhm */
+
+struct ina209_data {
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated;     /* in jiffies */
+
+       u16 regs[INA209_REGISTERS];     /* All chip registers */
+
+       u16 config_orig;                /* Original configuration */
+       u16 calibration_orig;           /* Original calibration */
+       u16 update_interval;
+};
+
+static struct ina209_data *ina209_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina209_data *data = i2c_get_clientdata(client);
+       struct ina209_data *ret = data;
+       s32 val;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (!data->valid ||
+           time_after(jiffies, data->last_updated + data->update_interval)) {
+               for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+                       val = i2c_smbus_read_word_swapped(client, i);
+                       if (val < 0) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->regs[i] = val;
+               }
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+/*
+ * Read a value from a device register and convert it to the
+ * appropriate sysfs units
+ */
+static long ina209_from_reg(const u8 reg, const u16 val)
+{
+       switch (reg) {
+       case INA209_SHUNT_VOLTAGE:
+       case INA209_SHUNT_VOLTAGE_POS_PEAK:
+       case INA209_SHUNT_VOLTAGE_NEG_PEAK:
+       case INA209_SHUNT_VOLTAGE_POS_WARN:
+       case INA209_SHUNT_VOLTAGE_NEG_WARN:
+               /* LSB=10 uV. Convert to mV. */
+               return DIV_ROUND_CLOSEST(val, 100);
+
+       case INA209_BUS_VOLTAGE:
+       case INA209_BUS_VOLTAGE_MAX_PEAK:
+       case INA209_BUS_VOLTAGE_MIN_PEAK:
+       case INA209_BUS_VOLTAGE_OVER_WARN:
+       case INA209_BUS_VOLTAGE_UNDER_WARN:
+       case INA209_BUS_VOLTAGE_OVER_LIMIT:
+       case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+               /* LSB=4 mV, last 3 bits unused */
+               return (val >> 3) * 4;
+
+       case INA209_CRITICAL_DAC_POS:
+               /* LSB=1 mV, in the upper 8 bits */
+               return val >> 8;
+
+       case INA209_CRITICAL_DAC_NEG:
+               /* LSB=1 mV, in the upper 8 bits */
+               return -1 * (val >> 8);
+
+       case INA209_POWER:
+       case INA209_POWER_PEAK:
+       case INA209_POWER_WARN:
+       case INA209_POWER_OVER_LIMIT:
+               /* LSB=20 mW. Convert to uW */
+               return val * 20 * 1000L;
+
+       case INA209_CURRENT:
+               /* LSB=1 mA (selected). Is in mA */
+               return val;
+       }
+
+       /* programmer goofed */
+       WARN_ON_ONCE(1);
+       return 0;
+}
+
+/*
+ * Take a value and convert it to register format, clamping the value
+ * to the appropriate range.
+ */
+static int ina209_to_reg(u8 reg, u16 old, long val)
+{
+       switch (reg) {
+       case INA209_SHUNT_VOLTAGE_POS_WARN:
+       case INA209_SHUNT_VOLTAGE_NEG_WARN:
+               /* Limit to +- 320 mV, 10 uV LSB */
+               return clamp_val(val, -320, 320) * 100;
+
+       case INA209_BUS_VOLTAGE_OVER_WARN:
+       case INA209_BUS_VOLTAGE_UNDER_WARN:
+       case INA209_BUS_VOLTAGE_OVER_LIMIT:
+       case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+               /*
+                * Limit to 0-32000 mV, 4 mV LSB
+                *
+                * The last three bits aren't part of the value, but we'll
+                * preserve them in their original state.
+                */
+               return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3)
+                 | (old & 0x7);
+
+       case INA209_CRITICAL_DAC_NEG:
+               /*
+                * Limit to -255-0 mV, 1 mV LSB
+                * Convert the value to a positive value for the register
+                *
+                * The value lives in the top 8 bits only, be careful
+                * and keep original value of other bits.
+                */
+               return (clamp_val(-val, 0, 255) << 8) | (old & 0xff);
+
+       case INA209_CRITICAL_DAC_POS:
+               /*
+                * Limit to 0-255 mV, 1 mV LSB
+                *
+                * The value lives in the top 8 bits only, be careful
+                * and keep original value of other bits.
+                */
+               return (clamp_val(val, 0, 255) << 8) | (old & 0xff);
+
+       case INA209_POWER_WARN:
+       case INA209_POWER_OVER_LIMIT:
+               /* 20 mW LSB */
+               return DIV_ROUND_CLOSEST(val, 20 * 1000);
+       }
+
+       /* Other registers are read-only, return access error */
+       return -EACCES;
+}
+
+static int ina209_interval_from_reg(u16 reg)
+{
+       return 68 >> (15 - ((reg >> 3) & 0x0f));
+}
+
+static u16 ina209_reg_from_interval(u16 config, long interval)
+{
+       int i, adc;
+
+       if (interval <= 0) {
+               adc = 8;
+       } else {
+               adc = 15;
+               for (i = 34 + 34 / 2; i; i >>= 1) {
+                       if (i < interval)
+                               break;
+                       adc--;
+               }
+       }
+       return (config & 0xf807) | (adc << 3) | (adc << 7);
+}
+
+static ssize_t ina209_set_interval(struct device *dev,
+                                  struct device_attribute *da,
+                                  const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina209_data *data = ina209_update_device(dev);
+       long val;
+       u16 regval;
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION],
+                                         val);
+       i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval);
+       data->regs[INA209_CONFIGURATION] = regval;
+       data->update_interval = ina209_interval_from_reg(regval);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t ina209_show_interval(struct device *dev,
+                                   struct device_attribute *da, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina209_data *data = i2c_get_clientdata(client);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
+}
+
+/*
+ * History is reset by writing 1 into bit 0 of the respective peak register.
+ * Since more than one peak register may be affected by the scope of a
+ * reset_history attribute write, use a bit mask in attr->index to identify
+ * which registers are affected.
+ */
+static u16 ina209_reset_history_regs[] = {
+       INA209_SHUNT_VOLTAGE_POS_PEAK,
+       INA209_SHUNT_VOLTAGE_NEG_PEAK,
+       INA209_BUS_VOLTAGE_MAX_PEAK,
+       INA209_BUS_VOLTAGE_MIN_PEAK,
+       INA209_POWER_PEAK
+};
+
+static ssize_t ina209_reset_history(struct device *dev,
+                                   struct device_attribute *da,
+                                   const char *buf,
+                                   size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina209_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       u32 mask = attr->index;
+       long val;
+       int i, ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) {
+               if (mask & (1 << i))
+                       i2c_smbus_write_word_swapped(client,
+                                       ina209_reset_history_regs[i], 1);
+       }
+       data->valid = false;
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t ina209_set_value(struct device *dev,
+                               struct device_attribute *da,
+                               const char *buf,
+                               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina209_data *data = ina209_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int reg = attr->index;
+       long val;
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       ret = ina209_to_reg(reg, data->regs[reg], val);
+       if (ret < 0) {
+               count = ret;
+               goto abort;
+       }
+       i2c_smbus_write_word_swapped(client, reg, ret);
+       data->regs[reg] = ret;
+abort:
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t ina209_show_value(struct device *dev,
+                                struct device_attribute *da,
+                                char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ina209_data *data = ina209_update_device(dev);
+       long val;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       val = ina209_from_reg(attr->index, data->regs[attr->index]);
+       return snprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t ina209_show_alarm(struct device *dev,
+                                struct device_attribute *da,
+                                char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ina209_data *data = ina209_update_device(dev);
+       const unsigned int mask = attr->index;
+       u16 status;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       status = data->regs[INA209_STATUS];
+
+       /*
+        * All alarms are in the INA209_STATUS register. To avoid a long
+        * switch statement, the mask is passed in attr->index
+        */
+       return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
+}
+
+/* Shunt voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL,
+                         INA209_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL,
+                         INA209_SHUNT_VOLTAGE_POS_PEAK);
+static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL,
+                         INA209_SHUNT_VOLTAGE_NEG_PEAK);
+static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL,
+                         ina209_reset_history, (1 << 0) | (1 << 1));
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN);
+static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_CRITICAL_DAC_POS);
+static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_CRITICAL_DAC_NEG);
+
+static SENSOR_DEVICE_ATTR(in0_min_alarm,  S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 11);
+static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 12);
+static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 6);
+static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 7);
+
+/* Bus voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL,
+                         INA209_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL,
+                         INA209_BUS_VOLTAGE_MAX_PEAK);
+static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL,
+                         INA209_BUS_VOLTAGE_MIN_PEAK);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+                         ina209_reset_history, (1 << 2) | (1 << 3));
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN);
+static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT);
+static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 14);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 15);
+static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 9);
+static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 10);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL,
+                         INA209_POWER);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value,
+                         NULL, INA209_POWER_PEAK);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+                         ina209_reset_history, 1 << 4);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_POWER_WARN);
+static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value,
+                         ina209_set_value, INA209_POWER_OVER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 13);
+static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL,
+                         1 << 8);
+
+/* Current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL,
+                         INA209_CURRENT);
+
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+                         ina209_show_interval, ina209_set_interval, 0);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ina209_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_input_highest.dev_attr.attr,
+       &sensor_dev_attr_in0_input_lowest.dev_attr.attr,
+       &sensor_dev_attr_in0_reset_history.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in0_crit_max.dev_attr.attr,
+       &sensor_dev_attr_in0_crit_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in0_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input_highest.dev_attr.attr,
+       &sensor_dev_attr_in1_input_lowest.dev_attr.attr,
+       &sensor_dev_attr_in1_reset_history.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_crit_max.dev_attr.attr,
+       &sensor_dev_attr_in1_crit_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_power1_input.dev_attr.attr,
+       &sensor_dev_attr_power1_input_highest.dev_attr.attr,
+       &sensor_dev_attr_power1_reset_history.dev_attr.attr,
+       &sensor_dev_attr_power1_max.dev_attr.attr,
+       &sensor_dev_attr_power1_crit.dev_attr.attr,
+       &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_power1_crit_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+
+       &sensor_dev_attr_update_interval.dev_attr.attr,
+
+       NULL,
+};
+
+static const struct attribute_group ina209_group = {
+       .attrs = ina209_attributes,
+};
+
+static void ina209_restore_conf(struct i2c_client *client,
+                               struct ina209_data *data)
+{
+       /* Restore initial configuration */
+       i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+                                    data->config_orig);
+       i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+                                    data->calibration_orig);
+}
+
+static int ina209_init_client(struct i2c_client *client,
+                             struct ina209_data *data)
+{
+       struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
+       u32 shunt;
+       int reg;
+
+       reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION);
+       if (reg < 0)
+               return reg;
+       data->calibration_orig = reg;
+
+       reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION);
+       if (reg < 0)
+               return reg;
+       data->config_orig = reg;
+
+       if (pdata) {
+               if (pdata->shunt_uohms <= 0)
+                       return -EINVAL;
+               shunt = pdata->shunt_uohms;
+       } else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor",
+                                        &shunt)) {
+               if (shunt == 0)
+                       return -EINVAL;
+       } else {
+               shunt = data->calibration_orig ?
+                 40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT;
+       }
+
+       i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+                                    INA209_CONFIG_DEFAULT);
+       data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT);
+
+       /*
+        * Calibrate current LSB to 1mA. Shunt is in uOhms.
+        * See equation 13 in datasheet.
+        */
+       i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+                                    clamp_val(40960000 / shunt, 1, 65535));
+
+       /* Clear status register */
+       i2c_smbus_read_word_swapped(client, INA209_STATUS);
+
+       return 0;
+}
+
+static int ina209_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct ina209_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       ret = ina209_init_client(client, data);
+       if (ret)
+               return ret;
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &ina209_group);
+       if (ret)
+               goto out_restore_conf;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto out_hwmon_device_register;
+       }
+
+       return 0;
+
+out_hwmon_device_register:
+       sysfs_remove_group(&client->dev.kobj, &ina209_group);
+out_restore_conf:
+       ina209_restore_conf(client, data);
+       return ret;
+}
+
+static int ina209_remove(struct i2c_client *client)
+{
+       struct ina209_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ina209_group);
+       ina209_restore_conf(client, data);
+
+       return 0;
+}
+
+static const struct i2c_device_id ina209_id[] = {
+       { "ina209", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ina209_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ina209_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ina209",
+       },
+       .probe          = ina209_probe,
+       .remove         = ina209_remove,
+       .id_table       = ina209_id,
+};
+
+module_i2c_driver(ina209_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("INA209 driver");
+MODULE_LICENSE("GPL");
index 117d66fcded6ae9fb9d6d28ac0d05aff67e480cb..37fc980fde240d7a7dd023cf27fc12aa8577a3f8 100644 (file)
@@ -19,6 +19,8 @@
  *            IT8726F  Super I/O chip w/LPC interface
  *            IT8728F  Super I/O chip w/LPC interface
  *            IT8758E  Super I/O chip w/LPC interface
+ *            IT8771E  Super I/O chip w/LPC interface
+ *            IT8772E  Super I/O chip w/LPC interface
  *            IT8782F  Super I/O chip w/LPC interface
  *            IT8783E/F Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
@@ -61,8 +63,8 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
-            it8783 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
+            it8772, it8782, it8783 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -140,6 +142,8 @@ static inline void superio_exit(void)
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT8728F_DEVID 0x8728
+#define IT8771E_DEVID 0x8771
+#define IT8772E_DEVID 0x8772
 #define IT8782F_DEVID 0x8782
 #define IT8783E_DEVID 0x8783
 #define IT87_ACT_REG  0x30
@@ -281,6 +285,24 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
                .peci_mask = 0x07,
        },
+       [it8771] = {
+               .name = "it8771",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+                                       /* PECI: guesswork */
+                                       /* 12mV ADC (OHM) */
+                                       /* 16 bit fans (OHM) */
+               .peci_mask = 0x07,
+       },
+       [it8772] = {
+               .name = "it8772",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+                                       /* PECI (coreboot) */
+                                       /* 12mV ADC (HWSensors4, OHM) */
+                                       /* 16 bit fans (HWSensors4, OHM) */
+               .peci_mask = 0x07,
+       },
        [it8782] = {
                .name = "it8782",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
@@ -384,7 +406,7 @@ static int adc_lsb(const struct it87_data *data, int nr)
 static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 {
        val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
-       return SENSORS_LIMIT(val, 0, 255);
+       return clamp_val(val, 0, 255);
 }
 
 static int in_from_reg(const struct it87_data *data, int nr, int val)
@@ -396,16 +418,15 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 {
        if (rpm == 0)
                return 255;
-       rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-                            254);
+       rpm = clamp_val(rpm, 1, 1000000);
+       return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline u16 FAN16_TO_REG(long rpm)
 {
        if (rpm == 0)
                return 0xffff;
-       return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+       return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
 }
 
 #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
@@ -414,8 +435,8 @@ static inline u16 FAN16_TO_REG(long rpm)
 #define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
                             1350000 / ((val) * 2))
 
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \
-                                       ((val) + 500) / 1000), -128, 127))
+#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
+                                   ((val) + 500) / 1000), -128, 127))
 #define TEMP_FROM_REG(val) ((val) * 1000)
 
 static u8 pwm_to_reg(const struct it87_data *data, long val)
@@ -1709,6 +1730,12 @@ static int __init it87_find(unsigned short *address,
        case IT8728F_DEVID:
                sio_data->type = it8728;
                break;
+       case IT8771E_DEVID:
+               sio_data->type = it8771;
+               break;
+       case IT8772E_DEVID:
+               sio_data->type = it8772;
+               break;
        case IT8782F_DEVID:
                sio_data->type = it8782;
                break;
@@ -1826,10 +1853,11 @@ static int __init it87_find(unsigned short *address,
 
                reg = superio_inb(IT87_SIO_GPIO3_REG);
                if (sio_data->type == it8721 || sio_data->type == it8728 ||
+                   sio_data->type == it8771 || sio_data->type == it8772 ||
                    sio_data->type == it8782) {
                        /*
                         * IT8721F/IT8758E, and IT8782F don't have VID pins
-                        * at all, not sure about the IT8728F.
+                        * at all, not sure about the IT8728F and compatibles.
                         */
                        sio_data->skip_vid = 1;
                } else {
@@ -1883,7 +1911,9 @@ static int __init it87_find(unsigned short *address,
                if (reg & (1 << 0))
                        sio_data->internal |= (1 << 0);
                if ((reg & (1 << 1)) || sio_data->type == it8721 ||
-                   sio_data->type == it8728)
+                   sio_data->type == it8728 ||
+                   sio_data->type == it8771 ||
+                   sio_data->type == it8772)
                        sio_data->internal |= (1 << 1);
 
                /*
index e21e43c13156911989267fb555d24e5b98ddb67e..4a58f130fd4e622cf840969920f5dfd62a393a2b 100644 (file)
@@ -103,6 +103,9 @@ static const unsigned short normal_i2c[] = {
 #define MCP98243_DEVID         0x2100
 #define MCP98243_DEVID_MASK    0xfffc
 
+#define MCP98244_DEVID         0x2200
+#define MCP98244_DEVID_MASK    0xfffc
+
 #define MCP9843_DEVID          0x0000  /* Also matches mcp9805 */
 #define MCP9843_DEVID_MASK     0xfffe
 
@@ -147,6 +150,7 @@ static struct jc42_chips jc42_chips[] = {
        { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
        { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
        { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
+       { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
        { MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
        { NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
        { ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
@@ -237,9 +241,9 @@ static struct i2c_driver jc42_driver = {
 
 static u16 jc42_temp_to_reg(int temp, bool extended)
 {
-       int ntemp = SENSORS_LIMIT(temp,
-                                 extended ? JC42_TEMP_MIN_EXTENDED :
-                                 JC42_TEMP_MIN, JC42_TEMP_MAX);
+       int ntemp = clamp_val(temp,
+                             extended ? JC42_TEMP_MIN_EXTENDED :
+                             JC42_TEMP_MIN, JC42_TEMP_MAX);
 
        /* convert from 0.001 to 0.0625 resolution */
        return (ntemp * 2 / 125) & 0x1fff;
index eed4d94017886626db4e08d0a231a15fcf1d96f0..f644a2e5759942a514696f0bbaeb89666a7524ea 100644 (file)
@@ -209,9 +209,9 @@ static inline int lut_temp_to_reg(struct lm63_data *data, long val)
 {
        val -= data->temp2_offset;
        if (data->lut_temp_highres)
-               return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
+               return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500);
        else
-               return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
+               return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
 }
 
 /*
@@ -415,7 +415,7 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
                return err;
 
        reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        data->pwm1[nr] = data->pwm_highres ? val :
@@ -700,7 +700,7 @@ static ssize_t set_update_interval(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+       lm63_set_convrate(client, data, clamp_val(val, 0, 100000));
        mutex_unlock(&data->update_lock);
 
        return count;
index 7272176a9ec786c397b6427d43ac42b10ff80fb2..9bde9644b102d9bcdade74ce20db444b832f9270 100644 (file)
@@ -8,6 +8,7 @@
  * Guillaume Ligneul <guillaume.ligneul@gmail.com>
  * Adrien Demarez <adrien.demarez@bolloretelecom.eu>
  * Jeremy Laine <jeremy.laine@bolloretelecom.eu>
+ * Chris Verges <kg4ysn@gmail.com>
  *
  * This software program is licensed subject to the GNU General Public License
  * (GPL).Version 2,June 1991, available at
@@ -36,11 +37,30 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
 
 #define LM73_ID                        0x9001  /* 0x0190, byte-swapped */
 #define DRVNAME                        "lm73"
-#define LM73_TEMP_MIN          (-40)
-#define LM73_TEMP_MAX          150
+#define LM73_TEMP_MIN          (-256000 / 250)
+#define LM73_TEMP_MAX          (255750 / 250)
 
-/*-----------------------------------------------------------------------*/
+#define LM73_CTRL_RES_SHIFT    5
+#define LM73_CTRL_RES_MASK     (BIT(5) | BIT(6))
+#define LM73_CTRL_TO_MASK      BIT(7)
+
+#define LM73_CTRL_HI_SHIFT     2
+#define LM73_CTRL_LO_SHIFT     1
+
+static const unsigned short lm73_convrates[] = {
+       14,     /* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
+       28,     /* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
+       56,     /* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
+       112,    /* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
+};
 
+struct lm73_data {
+       struct device *hwmon_dev;
+       struct mutex lock;
+       u8 ctrl;                        /* control register value */
+};
+
+/*-----------------------------------------------------------------------*/
 
 static ssize_t set_temp(struct device *dev, struct device_attribute *da,
                        const char *buf, size_t count)
@@ -56,8 +76,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
                return status;
 
        /* Write value */
-       value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
-               (LM73_TEMP_MAX*4)) << 5;
+       value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5;
        err = i2c_smbus_write_word_swapped(client, attr->index, value);
        return (err < 0) ? err : count;
 }
@@ -79,6 +98,73 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
        return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
 
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm73_data *data = i2c_get_clientdata(client);
+       unsigned long convrate;
+       s32 err;
+       int res = 0;
+
+       err = kstrtoul(buf, 10, &convrate);
+       if (err < 0)
+               return err;
+
+       /*
+        * Convert the desired conversion rate into register bits.
+        * res is already initialized, and everything past the second-to-last
+        * value in the array is treated as belonging to the last value
+        * in the array.
+        */
+       while (res < (ARRAY_SIZE(lm73_convrates) - 1) &&
+                       convrate > lm73_convrates[res])
+               res++;
+
+       mutex_lock(&data->lock);
+       data->ctrl &= LM73_CTRL_TO_MASK;
+       data->ctrl |= res << LM73_CTRL_RES_SHIFT;
+       err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl);
+       mutex_unlock(&data->lock);
+
+       if (err < 0)
+               return err;
+
+       return count;
+}
+
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+                            char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm73_data *data = i2c_get_clientdata(client);
+       int res;
+
+       res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
+}
+
+static ssize_t show_maxmin_alarm(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct lm73_data *data = i2c_get_clientdata(client);
+       s32 ctrl;
+
+       mutex_lock(&data->lock);
+       ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+       if (ctrl < 0)
+               goto abort;
+       data->ctrl = ctrl;
+       mutex_unlock(&data->lock);
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1);
+
+abort:
+       mutex_unlock(&data->lock);
+       return ctrl;
+}
 
 /*-----------------------------------------------------------------------*/
 
@@ -90,13 +176,20 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
                        show_temp, set_temp, LM73_REG_MIN);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
                        show_temp, NULL, LM73_REG_INPUT);
-
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+                       show_convrate, set_convrate, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+                       show_maxmin_alarm, NULL, LM73_CTRL_HI_SHIFT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+                       show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT);
 
 static struct attribute *lm73_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp1_min.dev_attr.attr,
-
+       &sensor_dev_attr_update_interval.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
        NULL
 };
 
@@ -111,23 +204,36 @@ static const struct attribute_group lm73_group = {
 static int
 lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       struct device *hwmon_dev;
        int status;
+       struct lm73_data *data;
+       int ctrl;
+
+       data = devm_kzalloc(&client->dev, sizeof(struct lm73_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->lock);
+
+       ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+       if (ctrl < 0)
+               return ctrl;
+       data->ctrl = ctrl;
 
        /* Register sysfs hooks */
        status = sysfs_create_group(&client->dev.kobj, &lm73_group);
        if (status)
                return status;
 
-       hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(hwmon_dev)) {
-               status = PTR_ERR(hwmon_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               status = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
-       i2c_set_clientdata(client, hwmon_dev);
 
        dev_info(&client->dev, "%s: sensor '%s'\n",
-                dev_name(hwmon_dev), client->name);
+                dev_name(data->hwmon_dev), client->name);
 
        return 0;
 
@@ -138,9 +244,9 @@ exit_remove:
 
 static int lm73_remove(struct i2c_client *client)
 {
-       struct device *hwmon_dev = i2c_get_clientdata(client);
+       struct lm73_data *data = i2c_get_clientdata(client);
 
-       hwmon_device_unregister(hwmon_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm73_group);
        return 0;
 }
index 89aa9098ba5b9ef1759c904752cff6f9cddf00e7..668ff4721323a22842b94823d17505da6bf68b27 100644 (file)
@@ -36,7 +36,7 @@
    REG: (0.5C/bit, two's complement) << 7 */
 static inline u16 LM75_TEMP_TO_REG(long temp)
 {
-       int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
+       int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
        ntemp += (ntemp < 0 ? -250 : 250);
        return (u16)((ntemp / 500) << 7);
 }
index f82acf67acf54c7180a35cd45b263615fc87a024..f17beb5e6dd63bd7055f35492546c452c2fedcb1 100644 (file)
@@ -101,7 +101,7 @@ static struct i2c_driver lm77_driver = {
  */
 static inline s16 LM77_TEMP_TO_REG(int temp)
 {
-       int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
+       int ntemp = clamp_val(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
        return (ntemp / 500) * 8;
 }
 
index 53d6ee8ffa3370e9cfc1e60049d9704e2eb5a7f2..483538fa1bd58644b68607039be7ef8ca0cb8ed5 100644 (file)
@@ -85,7 +85,7 @@ enum chips { lm78, lm79 };
  */
 static inline u8 IN_TO_REG(unsigned long val)
 {
-       unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+       unsigned long nval = clamp_val(val, 0, 4080);
        return (nval + 8) / 16;
 }
 #define IN_FROM_REG(val) ((val) *  16)
@@ -94,7 +94,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 {
        if (rpm <= 0)
                return 255;
-       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+       return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline int FAN_FROM_REG(u8 val, int div)
@@ -108,7 +108,7 @@ static inline int FAN_FROM_REG(u8 val, int div)
  */
 static inline s8 TEMP_TO_REG(int val)
 {
-       int nval = SENSORS_LIMIT(val, -128000, 127000) ;
+       int nval = clamp_val(val, -128000, 127000) ;
        return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000;
 }
 
index 28a8b71f45717a7a9d7ba68e34c3623426948bdb..357fbb9987284cf87fa3faf9bf05235a5427e5a1 100644 (file)
@@ -72,15 +72,15 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
  * Fixing this is just not worth it.
  */
 
-#define IN_TO_REG(val)         (SENSORS_LIMIT(((val) + 5) / 10, 0, 255))
+#define IN_TO_REG(val)         (clamp_val(((val) + 5) / 10, 0, 255))
 #define IN_FROM_REG(val)       ((val) * 10)
 
 static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
 {
        if (rpm == 0)
                return 255;
-       rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+       rpm = clamp_val(rpm, 1, 1000000);
+       return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
@@ -102,7 +102,7 @@ static inline long TEMP_FROM_REG(u16 temp)
 #define TEMP_LIMIT_FROM_REG(val)       (((val) > 0x80 ? \
        (val) - 0x100 : (val)) * 1000)
 
-#define TEMP_LIMIT_TO_REG(val)         SENSORS_LIMIT((val) < 0 ? \
+#define TEMP_LIMIT_TO_REG(val)         clamp_val((val) < 0 ? \
        ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
 
 #define DIV_FROM_REG(val)              (1 << (val))
index 9f2dd77e1e0e9b0025246156a68412ffb469bffb..47ade8ba152d5c0484e3927f4a1f416e20abaf64 100644 (file)
@@ -139,7 +139,7 @@ static const int lm85_scaling[] = {  /* .001 Volts */
 #define SCALE(val, from, to)   (((val) * (to) + ((from) / 2)) / (from))
 
 #define INS_TO_REG(n, val)     \
-               SENSORS_LIMIT(SCALE(val, lm85_scaling[n], 192), 0, 255)
+               clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255)
 
 #define INSEXT_FROM_REG(n, val, ext)   \
                SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
@@ -151,19 +151,19 @@ static inline u16 FAN_TO_REG(unsigned long val)
 {
        if (!val)
                return 0xffff;
-       return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+       return clamp_val(5400000 / val, 1, 0xfffe);
 }
 #define FAN_FROM_REG(val)      ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
                                 5400000 / (val))
 
 /* Temperature is reported in .001 degC increments */
 #define TEMP_TO_REG(val)       \
-               SENSORS_LIMIT(SCALE(val, 1000, 1), -127, 127)
+               clamp_val(SCALE(val, 1000, 1), -127, 127)
 #define TEMPEXT_FROM_REG(val, ext)     \
                SCALE(((val) << 4) + (ext), 16, 1000)
 #define TEMP_FROM_REG(val)     ((val) * 1000)
 
-#define PWM_TO_REG(val)                        SENSORS_LIMIT(val, 0, 255)
+#define PWM_TO_REG(val)                        clamp_val(val, 0, 255)
 #define PWM_FROM_REG(val)              (val)
 
 
@@ -258,7 +258,7 @@ static int ZONE_TO_REG(int zone)
        return i << 5;
 }
 
-#define HYST_TO_REG(val)       SENSORS_LIMIT(((val) + 500) / 1000, 0, 15)
+#define HYST_TO_REG(val)       clamp_val(((val) + 500) / 1000, 0, 15)
 #define HYST_FROM_REG(val)     ((val) * 1000)
 
 /*
index 863412a02bdd1484434583625d8670fa1d8b6079..8eeb141c85acdad04d23305cb581e76cef3d53fd 100644 (file)
@@ -931,7 +931,7 @@ static ssize_t set_update_interval(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+       lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
        mutex_unlock(&data->update_lock);
 
        return count;
index 1a003f73e4e4a8b96d4a87aa0dacecfb7ed15eff..b40f34cdb3caf34d9a72d3c7e90c334740c5c229 100644 (file)
@@ -371,8 +371,8 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 static u8 LM93_IN_TO_REG(int nr, unsigned val)
 {
        /* range limit */
-       const long mV = SENSORS_LIMIT(val,
-               lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+       const long mV = clamp_val(val,
+                                 lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
 
        /* try not to lose too much precision here */
        const long uV = mV * 1000;
@@ -385,8 +385,8 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
        const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
 
        u8 result = ((uV - intercept + (slope/2)) / slope);
-       result = SENSORS_LIMIT(result,
-                       lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+       result = clamp_val(result,
+                          lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
        return result;
 }
 
@@ -411,10 +411,10 @@ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
 {
        long uV_offset = vid * 1000 - val * 10000;
        if (upper) {
-               uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+               uV_offset = clamp_val(uV_offset, 12500, 200000);
                return (u8)((uV_offset /  12500 - 1) << 4);
        } else {
-               uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+               uV_offset = clamp_val(uV_offset, -400000, -25000);
                return (u8)((uV_offset / -25000 - 1) << 0);
        }
 }
@@ -437,7 +437,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
  */
 static u8 LM93_TEMP_TO_REG(long temp)
 {
-       int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+       int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
        ntemp += (ntemp < 0 ? -500 : 500);
        return (u8)(ntemp / 1000);
 }
@@ -472,7 +472,7 @@ static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
 {
        int factor = mode ? 5 : 10;
 
-       off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+       off = clamp_val(off, LM93_TEMP_OFFSET_MIN,
                mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
        return (u8)((off + factor/2) / factor);
 }
@@ -620,8 +620,8 @@ static u16 LM93_FAN_TO_REG(long rpm)
        if (rpm == 0) {
                count = 0x3fff;
        } else {
-               rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-               count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+               rpm = clamp_val(rpm, 1, 1000000);
+               count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe);
        }
 
        regs = count << 2;
@@ -692,7 +692,7 @@ static int LM93_RAMP_FROM_REG(u8 reg)
  */
 static u8 LM93_RAMP_TO_REG(int ramp)
 {
-       ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+       ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
        return (u8)((ramp + 2) / 5);
 }
 
@@ -702,7 +702,7 @@ static u8 LM93_RAMP_TO_REG(int ramp)
  */
 static u8 LM93_PROCHOT_TO_REG(long prochot)
 {
-       prochot = SENSORS_LIMIT(prochot, 0, 255);
+       prochot = clamp_val(prochot, 0, 255);
        return (u8)prochot;
 }
 
@@ -2052,7 +2052,7 @@ static ssize_t store_pwm_auto_channels(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+       data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255);
        lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1),
                                data->block9[nr][LM93_PWM_CTL1]);
        mutex_unlock(&data->update_lock);
@@ -2397,7 +2397,7 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev,
 
        mutex_lock(&data->update_lock);
        data->prochot_override = (data->prochot_override & 0xf0) |
-                                       SENSORS_LIMIT(val, 0, 15);
+                                       clamp_val(val, 0, 15);
        lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
                        data->prochot_override);
        mutex_unlock(&data->update_lock);
index 2915fd90836495c16cb4e89485daf5b457b6289b..a6c85f0ff8f3e5a9ebf099a8d251b95a7fe636d6 100644 (file)
@@ -259,7 +259,7 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
 
        val /= 1000;
 
-       val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+       val = clamp_val(val, 0, (index == 6 ? 127 : 255));
 
        mutex_lock(&data->update_lock);
 
@@ -284,7 +284,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
 
        val /= 1000;
 
-       val = SENSORS_LIMIT(val, 0, 31);
+       val = clamp_val(val, 0, 31);
 
        mutex_lock(&data->update_lock);
 
index e0019c69d1bbcd19b209446146356a82ba7926bb..2fa2c02f5569c5af563ac5a90e865917e648fdf2 100644 (file)
@@ -118,7 +118,7 @@ static inline int LIMIT_TO_MV(int limit, int range)
 
 static inline int MV_TO_LIMIT(int mv, int range)
 {
-       return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
+       return clamp_val(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
 }
 
 static inline int ADC_TO_CURR(int adc, int gain)
index 666d9f6263eb462e41a5ec319ca5d29dc67eb540..a7626358c95df29c2ccb62fa89ed23251acfb979 100644 (file)
@@ -215,7 +215,7 @@ static ssize_t set_temp_max(struct device *dev,
                return ret;
 
        mutex_lock(&data->update_lock);
-       data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       data->temp_max[index] = clamp_val(temp/1000, -128, 127);
        if (i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIMH_WR(index),
                                        data->temp_max[index]))
@@ -240,7 +240,7 @@ static ssize_t set_temp_min(struct device *dev,
                return ret;
 
        mutex_lock(&data->update_lock);
-       data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       data->temp_min[index] = clamp_val(temp/1000, -128, 127);
        if (i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIML_WR(index),
                                        data->temp_max[index]))
index 6e60036abfa724a8ea4773faf9f2dab18c902fce..3e7b4269f5b9df67658e5e3f855aaec6d95b3c29 100644 (file)
@@ -74,7 +74,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
 
 #define FAN_FROM_REG(val, rpm_range)   ((val) == 0 || (val) == 255 ? \
                                0 : (rpm_ranges[rpm_range] * 30) / (val))
-#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) / 1000, 0, 255)
+#define TEMP_LIMIT_TO_REG(val) clamp_val((val) / 1000, 0, 255)
 
 /*
  * Client data (each client gets its own)
@@ -312,7 +312,7 @@ static ssize_t set_pwm(struct device *dev,
        if (res)
                return res;
 
-       val = SENSORS_LIMIT(val, 0, 255);
+       val = clamp_val(val, 0, 255);
 
        mutex_lock(&data->update_lock);
        data->pwm[attr->index] = (u8)(val * 120 / 255);
index 223461a6d70f974ebeec806bc4c3cc8cb780088f..57d58cd3220682030fcb3f0d32b62e4e77648c04 100644 (file)
@@ -239,7 +239,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
+       data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255);
        i2c_smbus_write_byte_data(client, attr2->index,
                                  data->temp_high[attr2->nr]);
        mutex_unlock(&data->update_lock);
index f739f83bafb9d9e23c4d47f94655cb12d1a63ca1..3c16cbd4c00286d465bc2aed825330c0c89e9661 100644 (file)
@@ -245,7 +245,7 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
        if (err)
                return err;
 
-       rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+       rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
 
        /*
         * Divide the required speed by 60 to get from rpm to rps, then
@@ -313,7 +313,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        if (err)
                return err;
 
-       pwm = SENSORS_LIMIT(pwm, 0, 255);
+       pwm = clamp_val(pwm, 0, 255);
 
        mutex_lock(&data->update_lock);
 
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
new file mode 100644 (file)
index 0000000..bf4aa37
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * based on max1668.c
+ * Copyright (c) 2011 David George <david.george@ska.ac.za>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.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.h>
+
+#include <linux/platform_data/max6697.h>
+
+enum chips { max6581, max6602, max6622, max6636, max6689, max6693, max6694,
+            max6697, max6698, max6699 };
+
+/* Report local sensor as temp1 */
+
+static const u8 MAX6697_REG_TEMP[] = {
+                       0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08 };
+static const u8 MAX6697_REG_TEMP_EXT[] = {
+                       0x57, 0x09, 0x52, 0x53, 0x54, 0x55, 0x56, 0 };
+static const u8 MAX6697_REG_MAX[] = {
+                       0x17, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18 };
+static const u8 MAX6697_REG_CRIT[] = {
+                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 };
+
+/*
+ * Map device tree / platform data register bit map to chip bit map.
+ * Applies to alert register and over-temperature register.
+ */
+#define MAX6697_MAP_BITS(reg)  ((((reg) & 0x7e) >> 1) | \
+                                (((reg) & 0x01) << 6) | ((reg) & 0x80))
+
+#define MAX6697_REG_STAT(n)            (0x44 + (n))
+
+#define MAX6697_REG_CONFIG             0x41
+#define MAX6581_CONF_EXTENDED          (1 << 1)
+#define MAX6693_CONF_BETA              (1 << 2)
+#define MAX6697_CONF_RESISTANCE                (1 << 3)
+#define MAX6697_CONF_TIMEOUT           (1 << 5)
+#define MAX6697_REG_ALERT_MASK         0x42
+#define MAX6697_REG_OVERT_MASK         0x43
+
+#define MAX6581_REG_RESISTANCE         0x4a
+#define MAX6581_REG_IDEALITY           0x4b
+#define MAX6581_REG_IDEALITY_SELECT    0x4c
+#define MAX6581_REG_OFFSET             0x4d
+#define MAX6581_REG_OFFSET_SELECT      0x4e
+
+#define MAX6697_CONV_TIME              156     /* ms per channel, worst case */
+
+struct max6697_chip_data {
+       int channels;
+       u32 have_ext;
+       u32 have_crit;
+       u32 have_fault;
+       u8 valid_conf;
+       const u8 *alarm_map;
+};
+
+struct max6697_data {
+       struct device *hwmon_dev;
+
+       enum chips type;
+       const struct max6697_chip_data *chip;
+
+       int update_interval;    /* in milli-seconds */
+       int temp_offset;        /* in degrees C */
+
+       struct mutex update_lock;
+       unsigned long last_updated;     /* In jiffies */
+       bool valid;             /* true if following fields are valid */
+
+       /* 1x local and up to 7x remote */
+       u8 temp[8][4];          /* [nr][0]=temp [1]=ext [2]=max [3]=crit */
+#define MAX6697_TEMP_INPUT     0
+#define MAX6697_TEMP_EXT       1
+#define MAX6697_TEMP_MAX       2
+#define MAX6697_TEMP_CRIT      3
+       u32 alarms;
+};
+
+/* Diode fault status bits on MAX6581 are right shifted by one bit */
+static const u8 max6581_alarm_map[] = {
+        0, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 19, 20, 21, 22, 23 };
+
+static const struct max6697_chip_data max6697_chip_data[] = {
+       [max6581] = {
+               .channels = 8,
+               .have_crit = 0xff,
+               .have_ext = 0x7f,
+               .have_fault = 0xfe,
+               .valid_conf = MAX6581_CONF_EXTENDED | MAX6697_CONF_TIMEOUT,
+               .alarm_map = max6581_alarm_map,
+       },
+       [max6602] = {
+               .channels = 5,
+               .have_crit = 0x12,
+               .have_ext = 0x02,
+               .have_fault = 0x1e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6622] = {
+               .channels = 5,
+               .have_crit = 0x12,
+               .have_ext = 0x02,
+               .have_fault = 0x1e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6636] = {
+               .channels = 7,
+               .have_crit = 0x72,
+               .have_ext = 0x02,
+               .have_fault = 0x7e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6689] = {
+               .channels = 7,
+               .have_crit = 0x72,
+               .have_ext = 0x02,
+               .have_fault = 0x7e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6693] = {
+               .channels = 7,
+               .have_crit = 0x72,
+               .have_ext = 0x02,
+               .have_fault = 0x7e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+                 MAX6697_CONF_TIMEOUT,
+       },
+       [max6694] = {
+               .channels = 5,
+               .have_crit = 0x12,
+               .have_ext = 0x02,
+               .have_fault = 0x1e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+                 MAX6697_CONF_TIMEOUT,
+       },
+       [max6697] = {
+               .channels = 7,
+               .have_crit = 0x72,
+               .have_ext = 0x02,
+               .have_fault = 0x7e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6698] = {
+               .channels = 7,
+               .have_crit = 0x72,
+               .have_ext = 0x02,
+               .have_fault = 0x0e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+       [max6699] = {
+               .channels = 5,
+               .have_crit = 0x12,
+               .have_ext = 0x02,
+               .have_fault = 0x1e,
+               .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+       },
+};
+
+static struct max6697_data *max6697_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max6697_data *data = i2c_get_clientdata(client);
+       struct max6697_data *ret = data;
+       int val;
+       int i;
+       u32 alarms;
+
+       mutex_lock(&data->update_lock);
+
+       if (data->valid &&
+           !time_after(jiffies, data->last_updated
+                       + msecs_to_jiffies(data->update_interval)))
+               goto abort;
+
+       for (i = 0; i < data->chip->channels; i++) {
+               if (data->chip->have_ext & (1 << i)) {
+                       val = i2c_smbus_read_byte_data(client,
+                                                      MAX6697_REG_TEMP_EXT[i]);
+                       if (unlikely(val < 0)) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->temp[i][MAX6697_TEMP_EXT] = val;
+               }
+
+               val = i2c_smbus_read_byte_data(client, MAX6697_REG_TEMP[i]);
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp[i][MAX6697_TEMP_INPUT] = val;
+
+               val = i2c_smbus_read_byte_data(client, MAX6697_REG_MAX[i]);
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp[i][MAX6697_TEMP_MAX] = val;
+
+               if (data->chip->have_crit & (1 << i)) {
+                       val = i2c_smbus_read_byte_data(client,
+                                                      MAX6697_REG_CRIT[i]);
+                       if (unlikely(val < 0)) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->temp[i][MAX6697_TEMP_CRIT] = val;
+               }
+       }
+
+       alarms = 0;
+       for (i = 0; i < 3; i++) {
+               val = i2c_smbus_read_byte_data(client, MAX6697_REG_STAT(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               alarms = (alarms << 8) | val;
+       }
+       data->alarms = alarms;
+       data->last_updated = jiffies;
+       data->valid = true;
+abort:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max6697_data *data = max6697_update_device(dev);
+       int temp;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       temp = (data->temp[index][MAX6697_TEMP_INPUT] - data->temp_offset) << 3;
+       temp |= data->temp[index][MAX6697_TEMP_EXT] >> 5;
+
+       return sprintf(buf, "%d\n", temp * 125);
+}
+
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
+       struct max6697_data *data = max6697_update_device(dev);
+       int temp;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       temp = data->temp[nr][index];
+       temp -= data->temp_offset;
+
+       return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct max6697_data *data = max6697_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       if (data->chip->alarm_map)
+               index = data->chip->alarm_map[index];
+
+       return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t set_temp(struct device *dev,
+                       struct device_attribute *devattr,
+                       const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max6697_data *data = i2c_get_clientdata(client);
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset;
+       temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127);
+       data->temp[nr][index] = temp;
+       ret = i2c_smbus_write_byte_data(client,
+                                       index == 2 ? MAX6697_REG_MAX[nr]
+                                                  : MAX6697_REG_CRIT[nr],
+                                       temp);
+       mutex_unlock(&data->update_lock);
+
+       return ret < 0 ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_input, NULL, 6);
+static SENSOR_DEVICE_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           6, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           6, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_input, NULL, 7);
+static SENSOR_DEVICE_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           7, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           7, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp7_max_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp8_max_alarm, S_IRUGO, show_alarm, NULL, 23);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp7_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp8_crit_alarm, S_IRUGO, show_alarm, NULL, 15);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
+
+static struct attribute *max6697_attributes[8][7] = {
+       {
+               &sensor_dev_attr_temp1_input.dev_attr.attr,
+               &sensor_dev_attr_temp1_max.dev_attr.attr,
+               &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp1_crit.dev_attr.attr,
+               &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp2_input.dev_attr.attr,
+               &sensor_dev_attr_temp2_max.dev_attr.attr,
+               &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp2_crit.dev_attr.attr,
+               &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp2_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp3_input.dev_attr.attr,
+               &sensor_dev_attr_temp3_max.dev_attr.attr,
+               &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp3_crit.dev_attr.attr,
+               &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp3_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp4_input.dev_attr.attr,
+               &sensor_dev_attr_temp4_max.dev_attr.attr,
+               &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp4_crit.dev_attr.attr,
+               &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp4_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp5_input.dev_attr.attr,
+               &sensor_dev_attr_temp5_max.dev_attr.attr,
+               &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp5_crit.dev_attr.attr,
+               &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp5_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp6_input.dev_attr.attr,
+               &sensor_dev_attr_temp6_max.dev_attr.attr,
+               &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp6_crit.dev_attr.attr,
+               &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp6_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp7_input.dev_attr.attr,
+               &sensor_dev_attr_temp7_max.dev_attr.attr,
+               &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp7_crit.dev_attr.attr,
+               &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp7_fault.dev_attr.attr,
+               NULL
+       }, {
+               &sensor_dev_attr_temp8_input.dev_attr.attr,
+               &sensor_dev_attr_temp8_max.dev_attr.attr,
+               &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp8_crit.dev_attr.attr,
+               &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+               &sensor_dev_attr_temp8_fault.dev_attr.attr,
+               NULL
+       }
+};
+
+static const struct attribute_group max6697_group[8] = {
+       { .attrs = max6697_attributes[0] },
+       { .attrs = max6697_attributes[1] },
+       { .attrs = max6697_attributes[2] },
+       { .attrs = max6697_attributes[3] },
+       { .attrs = max6697_attributes[4] },
+       { .attrs = max6697_attributes[5] },
+       { .attrs = max6697_attributes[6] },
+       { .attrs = max6697_attributes[7] },
+};
+
+static void max6697_get_config_of(struct device_node *node,
+                                 struct max6697_platform_data *pdata)
+{
+       int len;
+       const __be32 *prop;
+
+       prop = of_get_property(node, "smbus-timeout-disable", &len);
+       if (prop)
+               pdata->smbus_timeout_disable = true;
+       prop = of_get_property(node, "extended-range-enable", &len);
+       if (prop)
+               pdata->extended_range_enable = true;
+       prop = of_get_property(node, "beta-compensation-enable", &len);
+       if (prop)
+               pdata->beta_compensation = true;
+       prop = of_get_property(node, "alert-mask", &len);
+       if (prop && len == sizeof(u32))
+               pdata->alert_mask = be32_to_cpu(prop[0]);
+       prop = of_get_property(node, "over-temperature-mask", &len);
+       if (prop && len == sizeof(u32))
+               pdata->over_temperature_mask = be32_to_cpu(prop[0]);
+       prop = of_get_property(node, "resistance-cancellation", &len);
+       if (prop) {
+               if (len == sizeof(u32))
+                       pdata->resistance_cancellation = be32_to_cpu(prop[0]);
+               else
+                       pdata->resistance_cancellation = 0xfe;
+       }
+       prop = of_get_property(node, "transistor-ideality", &len);
+       if (prop && len == 2 * sizeof(u32)) {
+                       pdata->ideality_mask = be32_to_cpu(prop[0]);
+                       pdata->ideality_value = be32_to_cpu(prop[1]);
+       }
+}
+
+static int max6697_init_chip(struct i2c_client *client)
+{
+       struct max6697_data *data = i2c_get_clientdata(client);
+       struct max6697_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct max6697_platform_data p;
+       const struct max6697_chip_data *chip = data->chip;
+       int factor = chip->channels;
+       int ret, reg;
+
+       /*
+        * Don't touch configuration if neither platform data nor OF
+        * configuration was specified. If that is the case, use the
+        * current chip configuration.
+        */
+       if (!pdata && !client->dev.of_node) {
+               reg = i2c_smbus_read_byte_data(client, MAX6697_REG_CONFIG);
+               if (reg < 0)
+                       return reg;
+               if (data->type == max6581) {
+                       if (reg & MAX6581_CONF_EXTENDED)
+                               data->temp_offset = 64;
+                       reg = i2c_smbus_read_byte_data(client,
+                                                      MAX6581_REG_RESISTANCE);
+                       if (reg < 0)
+                               return reg;
+                       factor += hweight8(reg);
+               } else {
+                       if (reg & MAX6697_CONF_RESISTANCE)
+                               factor++;
+               }
+               goto done;
+       }
+
+       if (client->dev.of_node) {
+               memset(&p, 0, sizeof(p));
+               max6697_get_config_of(client->dev.of_node, &p);
+               pdata = &p;
+       }
+
+       reg = 0;
+       if (pdata->smbus_timeout_disable &&
+           (chip->valid_conf & MAX6697_CONF_TIMEOUT)) {
+               reg |= MAX6697_CONF_TIMEOUT;
+       }
+       if (pdata->extended_range_enable &&
+           (chip->valid_conf & MAX6581_CONF_EXTENDED)) {
+               reg |= MAX6581_CONF_EXTENDED;
+               data->temp_offset = 64;
+       }
+       if (pdata->resistance_cancellation &&
+           (chip->valid_conf & MAX6697_CONF_RESISTANCE)) {
+               reg |= MAX6697_CONF_RESISTANCE;
+               factor++;
+       }
+       if (pdata->beta_compensation &&
+           (chip->valid_conf & MAX6693_CONF_BETA)) {
+               reg |= MAX6693_CONF_BETA;
+       }
+
+       ret = i2c_smbus_write_byte_data(client, MAX6697_REG_CONFIG, reg);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK,
+                                       MAX6697_MAP_BITS(pdata->alert_mask));
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK,
+                               MAX6697_MAP_BITS(pdata->over_temperature_mask));
+       if (ret < 0)
+               return ret;
+
+       if (data->type == max6581) {
+               factor += hweight8(pdata->resistance_cancellation >> 1);
+               ret = i2c_smbus_write_byte_data(client, MAX6581_REG_RESISTANCE,
+                                       pdata->resistance_cancellation >> 1);
+               if (ret < 0)
+                       return ret;
+               ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
+                                               pdata->ideality_mask >> 1);
+               if (ret < 0)
+                       return ret;
+               ret = i2c_smbus_write_byte_data(client,
+                                               MAX6581_REG_IDEALITY_SELECT,
+                                               pdata->ideality_value);
+               if (ret < 0)
+                       return ret;
+       }
+done:
+       data->update_interval = factor * MAX6697_CONV_TIME;
+       return 0;
+}
+
+static void max6697_remove_files(struct i2c_client *client)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
+               sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
+}
+
+static int max6697_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct device *dev = &client->dev;
+       struct max6697_data *data;
+       int i, err;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(dev, sizeof(struct max6697_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->type = id->driver_data;
+       data->chip = &max6697_chip_data[data->type];
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       err = max6697_init_chip(client);
+       if (err)
+               return err;
+
+       for (i = 0; i < data->chip->channels; i++) {
+               err = sysfs_create_file(&dev->kobj,
+                                       max6697_attributes[i][0]);
+               if (err)
+                       goto error;
+               err = sysfs_create_file(&dev->kobj,
+                                       max6697_attributes[i][1]);
+               if (err)
+                       goto error;
+               err = sysfs_create_file(&dev->kobj,
+                                       max6697_attributes[i][2]);
+               if (err)
+                       goto error;
+
+               if (data->chip->have_crit & (1 << i)) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               max6697_attributes[i][3]);
+                       if (err)
+                               goto error;
+                       err = sysfs_create_file(&dev->kobj,
+                                               max6697_attributes[i][4]);
+                       if (err)
+                               goto error;
+               }
+               if (data->chip->have_fault & (1 << i)) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               max6697_attributes[i][5]);
+                       if (err)
+                               goto error;
+               }
+       }
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       max6697_remove_files(client);
+       return err;
+}
+
+static int max6697_remove(struct i2c_client *client)
+{
+       struct max6697_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       max6697_remove_files(client);
+
+       return 0;
+}
+
+static const struct i2c_device_id max6697_id[] = {
+       { "max6581", max6581 },
+       { "max6602", max6602 },
+       { "max6622", max6622 },
+       { "max6636", max6636 },
+       { "max6689", max6689 },
+       { "max6693", max6693 },
+       { "max6694", max6694 },
+       { "max6697", max6697 },
+       { "max6698", max6698 },
+       { "max6699", max6699 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max6697_id);
+
+static struct i2c_driver max6697_driver = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "max6697",
+       },
+       .probe = max6697_probe,
+       .remove = max6697_remove,
+       .id_table = max6697_id,
+};
+
+module_i2c_driver(max6697_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("MAX6697 temperature sensor driver");
+MODULE_LICENSE("GPL");
index a87eb8986e360d66cebc31fca6e9ba90af32b538..b5f63f9c0ce1754f6c1b6a614e7c402f24382b81 100644 (file)
@@ -43,7 +43,7 @@ struct ntc_compensation {
  * The following compensation tables are from the specification of Murata NTC
  * Thermistors Datasheet
  */
-const struct ntc_compensation ncpXXwb473[] = {
+static const struct ntc_compensation ncpXXwb473[] = {
        { .temp_C       = -40, .ohm     = 1747920 },
        { .temp_C       = -35, .ohm     = 1245428 },
        { .temp_C       = -30, .ohm     = 898485 },
@@ -79,7 +79,7 @@ const struct ntc_compensation ncpXXwb473[] = {
        { .temp_C       = 120, .ohm     = 1615 },
        { .temp_C       = 125, .ohm     = 1406 },
 };
-const struct ntc_compensation ncpXXwl333[] = {
+static const struct ntc_compensation ncpXXwl333[] = {
        { .temp_C       = -40, .ohm     = 1610154 },
        { .temp_C       = -35, .ohm     = 1130850 },
        { .temp_C       = -30, .ohm     = 802609 },
index 60745a535821d3b787af31a00cfcecd41743c7ec..4f9eb0af5229b0e47dbbc7ad27d51d792de9bbb7 100644 (file)
@@ -72,7 +72,7 @@ config SENSORS_MAX34440
        default n
        help
          If you say yes here you get hardware monitoring support for Maxim
-         MAX34440, MAX34441, and MAX34446.
+         MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461.
 
          This driver can also be built as a module. If so, the module will
          be called max34440.
index 2ada7b021fbe4d1d5570ee2f0eba9b055a4e223a..7e930c3ce1abf011621669e1f054fcdf991c8e13 100644 (file)
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for Maxim MAX34440/MAX34441
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,7 +26,7 @@
 #include <linux/i2c.h>
 #include "pmbus.h"
 
-enum chips { max34440, max34441, max34446 };
+enum chips { max34440, max34441, max34446, max34460, max34461 };
 
 #define MAX34440_MFR_VOUT_PEAK         0xd4
 #define MAX34440_MFR_IOUT_PEAK         0xd5
@@ -87,7 +88,8 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
                                           MAX34446_MFR_POUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_AVG:
-               if (data->id != max34446)
+               if (data->id != max34446 && data->id != max34460 &&
+                   data->id != max34461)
                        return -ENXIO;
                ret = pmbus_read_word_data(client, page,
                                           MAX34446_MFR_TEMPERATURE_AVG);
@@ -322,6 +324,73 @@ static struct pmbus_driver_info max34440_info[] = {
                .read_word_data = max34440_read_word_data,
                .write_word_data = max34440_write_word_data,
        },
+       [max34460] = {
+               .pages = 18,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .m[PSC_VOLTAGE_OUT] = 1,
+               .b[PSC_VOLTAGE_OUT] = 0,
+               .R[PSC_VOLTAGE_OUT] = 3,
+               .m[PSC_TEMPERATURE] = 1,
+               .b[PSC_TEMPERATURE] = 0,
+               .R[PSC_TEMPERATURE] = 2,
+               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
+       },
+       [max34461] = {
+               .pages = 23,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .m[PSC_VOLTAGE_OUT] = 1,
+               .b[PSC_VOLTAGE_OUT] = 0,
+               .R[PSC_VOLTAGE_OUT] = 3,
+               .m[PSC_TEMPERATURE] = 1,
+               .b[PSC_TEMPERATURE] = 0,
+               .R[PSC_TEMPERATURE] = 2,
+               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               .func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+               /* page 16 is reserved */
+               .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
+       },
 };
 
 static int max34440_probe(struct i2c_client *client,
@@ -343,6 +412,8 @@ static const struct i2c_device_id max34440_id[] = {
        {"max34440", max34440},
        {"max34441", max34441},
        {"max34446", max34446},
+       {"max34460", max34460},
+       {"max34461", max34461},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, max34440_id);
index 3fe03dc47eb7f3753052dac8eed9d56456d4f529..fa9beb3eb60ca2a33cc6150542dfcbbc90b84219 100644 (file)
@@ -2,6 +2,7 @@
  * pmbus.h - Common defines and structures for PMBus devices
  *
  * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #define PMBUS_VIRT_READ_TEMP2_MAX      (PMBUS_VIRT_BASE + 28)
 #define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29)
 
+#define PMBUS_VIRT_READ_VMON           (PMBUS_VIRT_BASE + 30)
+#define PMBUS_VIRT_VMON_UV_WARN_LIMIT  (PMBUS_VIRT_BASE + 31)
+#define PMBUS_VIRT_VMON_OV_WARN_LIMIT  (PMBUS_VIRT_BASE + 32)
+#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33)
+#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34)
+#define PMBUS_VIRT_STATUS_VMON         (PMBUS_VIRT_BASE + 35)
+
 /*
  * CAPABILITY
  */
@@ -317,6 +325,8 @@ enum pmbus_sensor_classes {
 #define PMBUS_HAVE_STATUS_TEMP (1 << 15)
 #define PMBUS_HAVE_STATUS_FAN12        (1 << 16)
 #define PMBUS_HAVE_STATUS_FAN34        (1 << 17)
+#define PMBUS_HAVE_VMON                (1 << 18)
+#define PMBUS_HAVE_STATUS_VMON (1 << 19)
 
 enum pmbus_data_format { linear = 0, direct, vid };
 
@@ -359,6 +369,7 @@ struct pmbus_driver_info {
 
 /* Function declarations */
 
+void pmbus_clear_cache(struct i2c_client *client);
 int pmbus_set_page(struct i2c_client *client, u8 page);
 int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
 int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
index 7d19b1bb9ce6acf7de556c93fefb685501a195e1..80eef50c50fd27f9022f3f3176ff6434ad945867 100644 (file)
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for PMBus devices
  *
  * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "pmbus.h"
 
 /*
- * Constants needed to determine number of sensors, booleans, and labels.
+ * Number of additional attribute pointers to allocate
+ * with each call to krealloc
  */
-#define PMBUS_MAX_INPUT_SENSORS                22      /* 10*volt, 7*curr, 5*power */
-#define PMBUS_VOUT_SENSORS_PER_PAGE    9       /* input, min, max, lcrit,
-                                                  crit, lowest, highest, avg,
-                                                  reset */
-#define PMBUS_IOUT_SENSORS_PER_PAGE    8       /* input, min, max, crit,
-                                                  lowest, highest, avg,
-                                                  reset */
-#define PMBUS_POUT_SENSORS_PER_PAGE    7       /* input, cap, max, crit,
-                                                * highest, avg, reset
-                                                */
-#define PMBUS_MAX_SENSORS_PER_FAN      1       /* input */
-#define PMBUS_MAX_SENSORS_PER_TEMP     9       /* input, min, max, lcrit,
-                                                * crit, lowest, highest, avg,
-                                                * reset
-                                                */
-
-#define PMBUS_MAX_INPUT_BOOLEANS       7       /* v: min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm;
-                                                  c: alarm, crit_alarm;
-                                                  p: crit_alarm */
-#define PMBUS_VOUT_BOOLEANS_PER_PAGE   4       /* min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm */
-#define PMBUS_IOUT_BOOLEANS_PER_PAGE   3       /* alarm, lcrit_alarm,
-                                                  crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE   3       /* cap_alarm, alarm, crit_alarm
-                                                */
-#define PMBUS_MAX_BOOLEANS_PER_FAN     2       /* alarm, fault */
-#define PMBUS_MAX_BOOLEANS_PER_TEMP    4       /* min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm */
-
-#define PMBUS_MAX_INPUT_LABELS         4       /* vin, vcap, iin, pin */
-
-/*
- * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
- * are paged. status_input is unpaged.
- */
-#define PB_NUM_STATUS_REG      (PMBUS_PAGES * 6 + 1)
+#define PMBUS_ATTR_ALLOC_SIZE  32
 
 /*
  * Index into status register array, per status register group
 #define PB_STATUS_IOUT_BASE    (PB_STATUS_VOUT_BASE + PMBUS_PAGES)
 #define PB_STATUS_FAN_BASE     (PB_STATUS_IOUT_BASE + PMBUS_PAGES)
 #define PB_STATUS_FAN34_BASE   (PB_STATUS_FAN_BASE + PMBUS_PAGES)
-#define PB_STATUS_INPUT_BASE   (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
-#define PB_STATUS_TEMP_BASE    (PB_STATUS_INPUT_BASE + 1)
+#define PB_STATUS_TEMP_BASE    (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE   (PB_STATUS_TEMP_BASE + PMBUS_PAGES)
+#define PB_STATUS_VMON_BASE    (PB_STATUS_INPUT_BASE + 1)
+
+#define PB_NUM_STATUS_REG      (PB_STATUS_VMON_BASE + 1)
 
 #define PMBUS_NAME_SIZE                24
 
 struct pmbus_sensor {
+       struct pmbus_sensor *next;
        char name[PMBUS_NAME_SIZE];     /* sysfs sensor name */
-       struct sensor_device_attribute attribute;
+       struct device_attribute attribute;
        u8 page;                /* page number */
        u16 reg;                /* register */
        enum pmbus_sensor_classes class;        /* sensor class */
@@ -94,19 +64,28 @@ struct pmbus_sensor {
        int data;               /* Sensor data.
                                   Negative if there was a read error */
 };
+#define to_pmbus_sensor(_attr) \
+       container_of(_attr, struct pmbus_sensor, attribute)
 
 struct pmbus_boolean {
        char name[PMBUS_NAME_SIZE];     /* sysfs boolean name */
        struct sensor_device_attribute attribute;
+       struct pmbus_sensor *s1;
+       struct pmbus_sensor *s2;
 };
+#define to_pmbus_boolean(_attr) \
+       container_of(_attr, struct pmbus_boolean, attribute)
 
 struct pmbus_label {
        char name[PMBUS_NAME_SIZE];     /* sysfs label name */
-       struct sensor_device_attribute attribute;
+       struct device_attribute attribute;
        char label[PMBUS_NAME_SIZE];    /* label */
 };
+#define to_pmbus_label(_attr) \
+       container_of(_attr, struct pmbus_label, attribute)
 
 struct pmbus_data {
+       struct device *dev;
        struct device *hwmon_dev;
 
        u32 flags;              /* from platform data */
@@ -117,29 +96,9 @@ struct pmbus_data {
 
        int max_attributes;
        int num_attributes;
-       struct attribute **attributes;
        struct attribute_group group;
 
-       /*
-        * Sensors cover both sensor and limit registers.
-        */
-       int max_sensors;
-       int num_sensors;
        struct pmbus_sensor *sensors;
-       /*
-        * Booleans are used for alarms.
-        * Values are determined from status registers.
-        */
-       int max_booleans;
-       int num_booleans;
-       struct pmbus_boolean *booleans;
-       /*
-        * Labels are used to map generic names (e.g., "in1")
-        * to PMBus specific names (e.g., "vin" or "vout1").
-        */
-       int max_labels;
-       int num_labels;
-       struct pmbus_label *labels;
 
        struct mutex update_lock;
        bool valid;
@@ -150,10 +109,19 @@ struct pmbus_data {
         * so we keep them all together.
         */
        u8 status[PB_NUM_STATUS_REG];
+       u8 status_register;
 
        u8 currpage;
 };
 
+void pmbus_clear_cache(struct i2c_client *client)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+
+       data->valid = false;
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_cache);
+
 int pmbus_set_page(struct i2c_client *client, u8 page)
 {
        struct pmbus_data *data = i2c_get_clientdata(client);
@@ -318,9 +286,10 @@ EXPORT_SYMBOL_GPL(pmbus_clear_faults);
 
 static int pmbus_check_status_cml(struct i2c_client *client)
 {
+       struct pmbus_data *data = i2c_get_clientdata(client);
        int status, status2;
 
-       status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+       status = _pmbus_read_byte_data(client, -1, data->status_register);
        if (status < 0 || (status & PB_STATUS_CML)) {
                status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
                if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
@@ -329,29 +298,30 @@ static int pmbus_check_status_cml(struct i2c_client *client)
        return 0;
 }
 
-bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+static bool pmbus_check_register(struct i2c_client *client,
+                                int (*func)(struct i2c_client *client,
+                                            int page, int reg),
+                                int page, int reg)
 {
        int rv;
        struct pmbus_data *data = i2c_get_clientdata(client);
 
-       rv = _pmbus_read_byte_data(client, page, reg);
+       rv = func(client, page, reg);
        if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
                rv = pmbus_check_status_cml(client);
        pmbus_clear_fault_page(client, -1);
        return rv >= 0;
 }
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+       return pmbus_check_register(client, _pmbus_read_byte_data, page, reg);
+}
 EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
 
 bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
 {
-       int rv;
-       struct pmbus_data *data = i2c_get_clientdata(client);
-
-       rv = _pmbus_read_word_data(client, page, reg);
-       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-               rv = pmbus_check_status_cml(client);
-       pmbus_clear_fault_page(client, -1);
-       return rv >= 0;
+       return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
 }
 EXPORT_SYMBOL_GPL(pmbus_check_word_register);
 
@@ -363,53 +333,43 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
 }
 EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
 
+static struct _pmbus_status {
+       u32 func;
+       u16 base;
+       u16 reg;
+} pmbus_status[] = {
+       { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT },
+       { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT },
+       { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE,
+         PMBUS_STATUS_TEMPERATURE },
+       { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 },
+       { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 },
+};
+
 static struct pmbus_data *pmbus_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct pmbus_data *data = i2c_get_clientdata(client);
        const struct pmbus_driver_info *info = data->info;
+       struct pmbus_sensor *sensor;
 
        mutex_lock(&data->update_lock);
        if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               int i;
+               int i, j;
 
-               for (i = 0; i < info->pages; i++)
+               for (i = 0; i < info->pages; i++) {
                        data->status[PB_STATUS_BASE + i]
                            = _pmbus_read_byte_data(client, i,
-                                                   PMBUS_STATUS_BYTE);
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
-                               continue;
-                       data->status[PB_STATUS_VOUT_BASE + i]
-                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
-                               continue;
-                       data->status[PB_STATUS_IOUT_BASE + i]
-                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
-                               continue;
-                       data->status[PB_STATUS_TEMP_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_TEMPERATURE);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
-                               continue;
-                       data->status[PB_STATUS_FAN_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_FAN_12);
-               }
-
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
-                               continue;
-                       data->status[PB_STATUS_FAN34_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_FAN_34);
+                                                   data->status_register);
+                       for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) {
+                               struct _pmbus_status *s = &pmbus_status[j];
+
+                               if (!(info->func[i] & s->func))
+                                       continue;
+                               data->status[s->base + i]
+                                       = _pmbus_read_byte_data(client, i,
+                                                               s->reg);
+                       }
                }
 
                if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
@@ -417,9 +377,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
                          = _pmbus_read_byte_data(client, 0,
                                                  PMBUS_STATUS_INPUT);
 
-               for (i = 0; i < data->num_sensors; i++) {
-                       struct pmbus_sensor *sensor = &data->sensors[i];
+               if (info->func[0] & PMBUS_HAVE_STATUS_VMON)
+                       data->status[PB_STATUS_VMON_BASE]
+                         = _pmbus_read_byte_data(client, 0,
+                                                 PMBUS_VIRT_STATUS_VMON);
 
+               for (sensor = data->sensors; sensor; sensor = sensor->next) {
                        if (!data->valid || sensor->update)
                                sensor->data
                                    = _pmbus_read_word_data(client,
@@ -657,7 +620,7 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
                              enum pmbus_sensor_classes class, long val)
 {
-       val = SENSORS_LIMIT(val, 500, 1600);
+       val = clamp_val(val, 500, 1600);
 
        return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
 }
@@ -684,25 +647,20 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
 
 /*
  * Return boolean calculated from converted data.
- * <index> defines a status register index and mask, and optionally
- * two sensor indexes.
- * The upper half-word references the two sensors,
- * two sensor indices.
- * The upper half-word references the two optional sensors,
- * the lower half word references status register and mask.
- * The function returns true if (status[reg] & mask) is true and,
- * if specified, if v1 >= v2.
- * To determine if an object exceeds upper limits, specify <v, limit>.
- * To determine if an object exceeds lower limits, specify <limit, v>.
+ * <index> defines a status register index and mask.
+ * The mask is in the lower 8 bits, the register index is in bits 8..23.
  *
- * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
- * index are set. s1 and s2 (the sensor index values) are zero in this case.
- * The function returns true if (status[reg] & mask) is true.
+ * The associated pmbus_boolean structure contains optional pointers to two
+ * sensor attributes. If specified, those attributes are compared against each
+ * other to determine if a limit has been exceeded.
  *
- * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
- * a specified limit has to be performed to determine the boolean result.
+ * If the sensor attribute pointers are NULL, the function returns true if
+ * (status[reg] & mask) is true.
+ *
+ * If sensor attribute pointers are provided, a comparison against a specified
+ * limit has to be performed to determine the boolean result.
  * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
- * sensor values referenced by sensor indices s1 and s2).
+ * sensor values referenced by sensor attribute pointers s1 and s2).
  *
  * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
  * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
@@ -710,11 +668,12 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
  * If a negative value is stored in any of the referenced registers, this value
  * reflects an error code which will be returned.
  */
-static int pmbus_get_boolean(struct pmbus_data *data, int index)
+static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,
+                            int index)
 {
-       u8 s1 = (index >> 24) & 0xff;
-       u8 s2 = (index >> 16) & 0xff;
-       u8 reg = (index >> 8) & 0xff;
+       struct pmbus_sensor *s1 = b->s1;
+       struct pmbus_sensor *s2 = b->s2;
+       u16 reg = (index >> 8) & 0xffff;
        u8 mask = index & 0xff;
        int ret, status;
        u8 regval;
@@ -724,21 +683,21 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index)
                return status;
 
        regval = status & mask;
-       if (!s1 && !s2)
+       if (!s1 && !s2) {
                ret = !!regval;
-       else {
+       } else if (!s1 || !s2) {
+               BUG();
+               return 0;
+       } else {
                long v1, v2;
-               struct pmbus_sensor *sensor1, *sensor2;
 
-               sensor1 = &data->sensors[s1];
-               if (sensor1->data < 0)
-                       return sensor1->data;
-               sensor2 = &data->sensors[s2];
-               if (sensor2->data < 0)
-                       return sensor2->data;
+               if (s1->data < 0)
+                       return s1->data;
+               if (s2->data < 0)
+                       return s2->data;
 
-               v1 = pmbus_reg2data(data, sensor1);
-               v2 = pmbus_reg2data(data, sensor2);
+               v1 = pmbus_reg2data(data, s1);
+               v2 = pmbus_reg2data(data, s2);
                ret = !!(regval && v1 >= v2);
        }
        return ret;
@@ -748,23 +707,22 @@ static ssize_t pmbus_show_boolean(struct device *dev,
                                  struct device_attribute *da, char *buf)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct pmbus_boolean *boolean = to_pmbus_boolean(attr);
        struct pmbus_data *data = pmbus_update_device(dev);
        int val;
 
-       val = pmbus_get_boolean(data, attr->index);
+       val = pmbus_get_boolean(data, boolean, attr->index);
        if (val < 0)
                return val;
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
 static ssize_t pmbus_show_sensor(struct device *dev,
-                                struct device_attribute *da, char *buf)
+                                struct device_attribute *devattr, char *buf)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct pmbus_data *data = pmbus_update_device(dev);
-       struct pmbus_sensor *sensor;
+       struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
 
-       sensor = &data->sensors[attr->index];
        if (sensor->data < 0)
                return sensor->data;
 
@@ -775,10 +733,9 @@ static ssize_t pmbus_set_sensor(struct device *dev,
                                struct device_attribute *devattr,
                                const char *buf, size_t count)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct pmbus_data *data = i2c_get_clientdata(client);
-       struct pmbus_sensor *sensor = &data->sensors[attr->index];
+       struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
        ssize_t rv = count;
        long val = 0;
        int ret;
@@ -793,7 +750,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,
        if (ret < 0)
                rv = ret;
        else
-               data->sensors[attr->index].data = regval;
+               sensor->data = regval;
        mutex_unlock(&data->update_lock);
        return rv;
 }
@@ -801,102 +758,130 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 static ssize_t pmbus_show_label(struct device *dev,
                                struct device_attribute *da, char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct pmbus_label *label = to_pmbus_label(da);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       data->labels[attr->index].label);
+       return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
 }
 
-#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set)   \
-do {                                                                   \
-       struct sensor_device_attribute *a                               \
-           = &data->_type##s[data->num_##_type##s].attribute;          \
-       BUG_ON(data->num_attributes >= data->max_attributes);           \
-       sysfs_attr_init(&a->dev_attr.attr);                             \
-       a->dev_attr.attr.name = _name;                                  \
-       a->dev_attr.attr.mode = _mode;                                  \
-       a->dev_attr.show = _show;                                       \
-       a->dev_attr.store = _set;                                       \
-       a->index = _idx;                                                \
-       data->attributes[data->num_attributes] = &a->dev_attr.attr;     \
-       data->num_attributes++;                                         \
-} while (0)
-
-#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx)                   \
-       PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type,               \
-                      pmbus_show_##_type,  NULL)
-
-#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx)                   \
-       PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type,     \
-                      pmbus_show_##_type, pmbus_set_##_type)
-
-static void pmbus_add_boolean(struct pmbus_data *data,
-                             const char *name, const char *type, int seq,
-                             int idx)
+static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
 {
-       struct pmbus_boolean *boolean;
-
-       BUG_ON(data->num_booleans >= data->max_booleans);
-
-       boolean = &data->booleans[data->num_booleans];
+       if (data->num_attributes >= data->max_attributes - 1) {
+               data->max_attributes += PMBUS_ATTR_ALLOC_SIZE;
+               data->group.attrs = krealloc(data->group.attrs,
+                                            sizeof(struct attribute *) *
+                                            data->max_attributes, GFP_KERNEL);
+               if (data->group.attrs == NULL)
+                       return -ENOMEM;
+       }
 
-       snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
-                name, seq, type);
-       PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
-       data->num_booleans++;
+       data->group.attrs[data->num_attributes++] = attr;
+       data->group.attrs[data->num_attributes] = NULL;
+       return 0;
 }
 
-static void pmbus_add_boolean_reg(struct pmbus_data *data,
-                                 const char *name, const char *type,
-                                 int seq, int reg, int bit)
+static void pmbus_dev_attr_init(struct device_attribute *dev_attr,
+                               const char *name,
+                               umode_t mode,
+                               ssize_t (*show)(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf),
+                               ssize_t (*store)(struct device *dev,
+                                                struct device_attribute *attr,
+                                                const char *buf, size_t count))
 {
-       pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
+       sysfs_attr_init(&dev_attr->attr);
+       dev_attr->attr.name = name;
+       dev_attr->attr.mode = mode;
+       dev_attr->show = show;
+       dev_attr->store = store;
 }
 
-static void pmbus_add_boolean_cmp(struct pmbus_data *data,
-                                 const char *name, const char *type,
-                                 int seq, int i1, int i2, int reg, int mask)
+static void pmbus_attr_init(struct sensor_device_attribute *a,
+                           const char *name,
+                           umode_t mode,
+                           ssize_t (*show)(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf),
+                           ssize_t (*store)(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t count),
+                           int idx)
 {
-       pmbus_add_boolean(data, name, type, seq,
-                         (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
+       pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store);
+       a->index = idx;
 }
 
-static void pmbus_add_sensor(struct pmbus_data *data,
+static int pmbus_add_boolean(struct pmbus_data *data,
                             const char *name, const char *type, int seq,
-                            int page, int reg, enum pmbus_sensor_classes class,
-                            bool update, bool readonly)
+                            struct pmbus_sensor *s1,
+                            struct pmbus_sensor *s2,
+                            u16 reg, u8 mask)
+{
+       struct pmbus_boolean *boolean;
+       struct sensor_device_attribute *a;
+
+       boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL);
+       if (!boolean)
+               return -ENOMEM;
+
+       a = &boolean->attribute;
+
+       snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
+                name, seq, type);
+       boolean->s1 = s1;
+       boolean->s2 = s2;
+       pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL,
+                       (reg << 8) | mask);
+
+       return pmbus_add_attribute(data, &a->dev_attr.attr);
+}
+
+static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+                                            const char *name, const char *type,
+                                            int seq, int page, int reg,
+                                            enum pmbus_sensor_classes class,
+                                            bool update, bool readonly)
 {
        struct pmbus_sensor *sensor;
+       struct device_attribute *a;
 
-       BUG_ON(data->num_sensors >= data->max_sensors);
+       sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+       if (!sensor)
+               return NULL;
+       a = &sensor->attribute;
 
-       sensor = &data->sensors[data->num_sensors];
        snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
                 name, seq, type);
        sensor->page = page;
        sensor->reg = reg;
        sensor->class = class;
        sensor->update = update;
-       if (readonly)
-               PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
-                                  data->num_sensors);
-       else
-               PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
-                                  data->num_sensors);
-       data->num_sensors++;
+       pmbus_dev_attr_init(a, sensor->name,
+                           readonly ? S_IRUGO : S_IRUGO | S_IWUSR,
+                           pmbus_show_sensor, pmbus_set_sensor);
+
+       if (pmbus_add_attribute(data, &a->attr))
+               return NULL;
+
+       sensor->next = data->sensors;
+       data->sensors = sensor;
+
+       return sensor;
 }
 
-static void pmbus_add_label(struct pmbus_data *data,
-                           const char *name, int seq,
-                           const char *lstring, int index)
+static int pmbus_add_label(struct pmbus_data *data,
+                          const char *name, int seq,
+                          const char *lstring, int index)
 {
        struct pmbus_label *label;
+       struct device_attribute *a;
 
-       BUG_ON(data->num_labels >= data->max_labels);
+       label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+       if (!label)
+               return -ENOMEM;
+
+       a = &label->attribute;
 
-       label = &data->labels[data->num_labels];
        snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
        if (!index)
                strncpy(label->label, lstring, sizeof(label->label) - 1);
@@ -904,65 +889,8 @@ static void pmbus_add_label(struct pmbus_data *data,
                snprintf(label->label, sizeof(label->label), "%s%d", lstring,
                         index);
 
-       PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
-       data->num_labels++;
-}
-
-/*
- * Determine maximum number of sensors, booleans, and labels.
- * To keep things simple, only make a rough high estimate.
- */
-static void pmbus_find_max_attr(struct i2c_client *client,
-                               struct pmbus_data *data)
-{
-       const struct pmbus_driver_info *info = data->info;
-       int page, max_sensors, max_booleans, max_labels;
-
-       max_sensors = PMBUS_MAX_INPUT_SENSORS;
-       max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
-       max_labels = PMBUS_MAX_INPUT_LABELS;
-
-       for (page = 0; page < info->pages; page++) {
-               if (info->func[page] & PMBUS_HAVE_VOUT) {
-                       max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_IOUT) {
-                       max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_POUT) {
-                       max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_FAN12) {
-                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-               }
-               if (info->func[page] & PMBUS_HAVE_FAN34) {
-                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP2) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP3) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-       }
-       data->max_sensors = max_sensors;
-       data->max_booleans = max_booleans;
-       data->max_labels = max_labels;
-       data->max_attributes = max_sensors + max_booleans + max_labels;
+       pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL);
+       return pmbus_add_attribute(data, &a->attr);
 }
 
 /*
@@ -975,12 +903,12 @@ static void pmbus_find_max_attr(struct i2c_client *client,
  */
 struct pmbus_limit_attr {
        u16 reg;                /* Limit register */
+       u16 sbit;               /* Alarm attribute status bit */
        bool update;            /* True if register needs updates */
        bool low;               /* True if low limit; for limits with compare
                                   functions only */
        const char *attr;       /* Attribute name */
        const char *alarm;      /* Alarm attribute name */
-       u32 sbit;               /* Alarm attribute status bit */
 };
 
 /*
@@ -988,7 +916,9 @@ struct pmbus_limit_attr {
  * description includes a reference to the associated limit attributes.
  */
 struct pmbus_sensor_attr {
-       u8 reg;                         /* sensor register */
+       u16 reg;                        /* sensor register */
+       u8 gbit;                        /* generic status bit */
+       u8 nlimit;                      /* # of limit registers */
        enum pmbus_sensor_classes class;/* sensor class */
        const char *label;              /* sensor label */
        bool paged;                     /* true if paged sensor */
@@ -997,47 +927,47 @@ struct pmbus_sensor_attr {
        u32 func;                       /* sensor mask */
        u32 sfunc;                      /* sensor status mask */
        int sbase;                      /* status base register */
-       u32 gbit;                       /* generic status bit */
        const struct pmbus_limit_attr *limit;/* limit registers */
-       int nlimit;                     /* # of limit registers */
 };
 
 /*
  * Add a set of limit attributes and, if supported, the associated
  * alarm attributes.
+ * returns 0 if no alarm register found, 1 if an alarm register was found,
+ * < 0 on errors.
  */
-static bool pmbus_add_limit_attrs(struct i2c_client *client,
-                                 struct pmbus_data *data,
-                                 const struct pmbus_driver_info *info,
-                                 const char *name, int index, int page,
-                                 int cbase,
-                                 const struct pmbus_sensor_attr *attr)
+static int pmbus_add_limit_attrs(struct i2c_client *client,
+                                struct pmbus_data *data,
+                                const struct pmbus_driver_info *info,
+                                const char *name, int index, int page,
+                                struct pmbus_sensor *base,
+                                const struct pmbus_sensor_attr *attr)
 {
        const struct pmbus_limit_attr *l = attr->limit;
        int nlimit = attr->nlimit;
-       bool have_alarm = false;
-       int i, cindex;
+       int have_alarm = 0;
+       int i, ret;
+       struct pmbus_sensor *curr;
 
        for (i = 0; i < nlimit; i++) {
                if (pmbus_check_word_register(client, page, l->reg)) {
-                       cindex = data->num_sensors;
-                       pmbus_add_sensor(data, name, l->attr, index, page,
-                                        l->reg, attr->class,
-                                        attr->update || l->update,
-                                        false);
+                       curr = pmbus_add_sensor(data, name, l->attr, index,
+                                               page, l->reg, attr->class,
+                                               attr->update || l->update,
+                                               false);
+                       if (!curr)
+                               return -ENOMEM;
                        if (l->sbit && (info->func[page] & attr->sfunc)) {
-                               if (attr->compare) {
-                                       pmbus_add_boolean_cmp(data, name,
-                                               l->alarm, index,
-                                               l->low ? cindex : cbase,
-                                               l->low ? cbase : cindex,
-                                               attr->sbase + page, l->sbit);
-                               } else {
-                                       pmbus_add_boolean_reg(data, name,
-                                               l->alarm, index,
-                                               attr->sbase + page, l->sbit);
-                               }
-                               have_alarm = true;
+                               ret = pmbus_add_boolean(data, name,
+                                       l->alarm, index,
+                                       attr->compare ?  l->low ? curr : base
+                                                     : NULL,
+                                       attr->compare ? l->low ? base : curr
+                                                     : NULL,
+                                       attr->sbase + page, l->sbit);
+                               if (ret)
+                                       return ret;
+                               have_alarm = 1;
                        }
                }
                l++;
@@ -1045,45 +975,59 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client,
        return have_alarm;
 }
 
-static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
-                                      struct pmbus_data *data,
-                                      const struct pmbus_driver_info *info,
-                                      const char *name,
-                                      int index, int page,
-                                      const struct pmbus_sensor_attr *attr)
+static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+                                     struct pmbus_data *data,
+                                     const struct pmbus_driver_info *info,
+                                     const char *name,
+                                     int index, int page,
+                                     const struct pmbus_sensor_attr *attr)
 {
-       bool have_alarm;
-       int cbase = data->num_sensors;
-
-       if (attr->label)
-               pmbus_add_label(data, name, index, attr->label,
-                               attr->paged ? page + 1 : 0);
-       pmbus_add_sensor(data, name, "input", index, page, attr->reg,
-                        attr->class, true, true);
+       struct pmbus_sensor *base;
+       int ret;
+
+       if (attr->label) {
+               ret = pmbus_add_label(data, name, index, attr->label,
+                                     attr->paged ? page + 1 : 0);
+               if (ret)
+                       return ret;
+       }
+       base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+                               attr->class, true, true);
+       if (!base)
+               return -ENOMEM;
        if (attr->sfunc) {
-               have_alarm = pmbus_add_limit_attrs(client, data, info, name,
-                                                  index, page, cbase, attr);
+               ret = pmbus_add_limit_attrs(client, data, info, name,
+                                           index, page, base, attr);
+               if (ret < 0)
+                       return ret;
                /*
                 * Add generic alarm attribute only if there are no individual
                 * alarm attributes, if there is a global alarm bit, and if
                 * the generic status register for this page is accessible.
                 */
-               if (!have_alarm && attr->gbit &&
-                   pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
-                       pmbus_add_boolean_reg(data, name, "alarm", index,
-                                             PB_STATUS_BASE + page,
-                                             attr->gbit);
+               if (!ret && attr->gbit &&
+                   pmbus_check_byte_register(client, page,
+                                             data->status_register)) {
+                       ret = pmbus_add_boolean(data, name, "alarm", index,
+                                               NULL, NULL,
+                                               PB_STATUS_BASE + page,
+                                               attr->gbit);
+                       if (ret)
+                               return ret;
+               }
        }
+       return 0;
 }
 
-static void pmbus_add_sensor_attrs(struct i2c_client *client,
-                                  struct pmbus_data *data,
-                                  const char *name,
-                                  const struct pmbus_sensor_attr *attrs,
-                                  int nattrs)
+static int pmbus_add_sensor_attrs(struct i2c_client *client,
+                                 struct pmbus_data *data,
+                                 const char *name,
+                                 const struct pmbus_sensor_attr *attrs,
+                                 int nattrs)
 {
        const struct pmbus_driver_info *info = data->info;
        int index, i;
+       int ret;
 
        index = 1;
        for (i = 0; i < nattrs; i++) {
@@ -1093,12 +1037,16 @@ static void pmbus_add_sensor_attrs(struct i2c_client *client,
                for (page = 0; page < pages; page++) {
                        if (!(info->func[page] & attrs->func))
                                continue;
-                       pmbus_add_sensor_attrs_one(client, data, info, name,
-                                                  index, page, attrs);
+                       ret = pmbus_add_sensor_attrs_one(client, data, info,
+                                                        name, index, page,
+                                                        attrs);
+                       if (ret)
+                               return ret;
                        index++;
                }
                attrs++;
        }
+       return 0;
 }
 
 static const struct pmbus_limit_attr vin_limit_attrs[] = {
@@ -1140,6 +1088,30 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
        },
 };
 
+static const struct pmbus_limit_attr vmon_limit_attrs[] = {
+       {
+               .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_VOLTAGE_UV_WARNING,
+       }, {
+               .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_VOLTAGE_UV_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_VOLTAGE_OV_WARNING,
+       }, {
+               .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_VOLTAGE_OV_FAULT,
+       }
+};
+
 static const struct pmbus_limit_attr vout_limit_attrs[] = {
        {
                .reg = PMBUS_VOUT_UV_WARN_LIMIT,
@@ -1190,6 +1162,15 @@ static const struct pmbus_sensor_attr voltage_attributes[] = {
                .gbit = PB_STATUS_VIN_UV,
                .limit = vin_limit_attrs,
                .nlimit = ARRAY_SIZE(vin_limit_attrs),
+       }, {
+               .reg = PMBUS_VIRT_READ_VMON,
+               .class = PSC_VOLTAGE_IN,
+               .label = "vmon",
+               .func = PMBUS_HAVE_VMON,
+               .sfunc = PMBUS_HAVE_STATUS_VMON,
+               .sbase = PB_STATUS_VMON_BASE,
+               .limit = vmon_limit_attrs,
+               .nlimit = ARRAY_SIZE(vmon_limit_attrs),
        }, {
                .reg = PMBUS_READ_VCAP,
                .class = PSC_VOLTAGE_IN,
@@ -1553,12 +1534,13 @@ static const u32 pmbus_fan_status_flags[] = {
 };
 
 /* Fans */
-static void pmbus_add_fan_attributes(struct i2c_client *client,
-                                    struct pmbus_data *data)
+static int pmbus_add_fan_attributes(struct i2c_client *client,
+                                   struct pmbus_data *data)
 {
        const struct pmbus_driver_info *info = data->info;
        int index = 1;
        int page;
+       int ret;
 
        for (page = 0; page < info->pages; page++) {
                int f;
@@ -1584,9 +1566,10 @@ static void pmbus_add_fan_attributes(struct i2c_client *client,
                            (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
                                continue;
 
-                       pmbus_add_sensor(data, "fan", "input", index, page,
-                                        pmbus_fan_registers[f], PSC_FAN, true,
-                                        true);
+                       if (pmbus_add_sensor(data, "fan", "input", index,
+                                            page, pmbus_fan_registers[f],
+                                            PSC_FAN, true, true) == NULL)
+                               return -ENOMEM;
 
                        /*
                         * Each fan status register covers multiple fans,
@@ -1601,39 +1584,55 @@ static void pmbus_add_fan_attributes(struct i2c_client *client,
                                        base = PB_STATUS_FAN34_BASE + page;
                                else
                                        base = PB_STATUS_FAN_BASE + page;
-                               pmbus_add_boolean_reg(data, "fan", "alarm",
-                                       index, base,
+                               ret = pmbus_add_boolean(data, "fan",
+                                       "alarm", index, NULL, NULL, base,
                                        PB_FAN_FAN1_WARNING >> (f & 1));
-                               pmbus_add_boolean_reg(data, "fan", "fault",
-                                       index, base,
+                               if (ret)
+                                       return ret;
+                               ret = pmbus_add_boolean(data, "fan",
+                                       "fault", index, NULL, NULL, base,
                                        PB_FAN_FAN1_FAULT >> (f & 1));
+                               if (ret)
+                                       return ret;
                        }
                        index++;
                }
        }
+       return 0;
 }
 
-static void pmbus_find_attributes(struct i2c_client *client,
-                                 struct pmbus_data *data)
+static int pmbus_find_attributes(struct i2c_client *client,
+                                struct pmbus_data *data)
 {
+       int ret;
+
        /* Voltage sensors */
-       pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
-                              ARRAY_SIZE(voltage_attributes));
+       ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+                                    ARRAY_SIZE(voltage_attributes));
+       if (ret)
+               return ret;
 
        /* Current sensors */
-       pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
-                              ARRAY_SIZE(current_attributes));
+       ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+                                    ARRAY_SIZE(current_attributes));
+       if (ret)
+               return ret;
 
        /* Power sensors */
-       pmbus_add_sensor_attrs(client, data, "power", power_attributes,
-                              ARRAY_SIZE(power_attributes));
+       ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+                                    ARRAY_SIZE(power_attributes));
+       if (ret)
+               return ret;
 
        /* Temperature sensors */
-       pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
-                              ARRAY_SIZE(temp_attributes));
+       ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+                                    ARRAY_SIZE(temp_attributes));
+       if (ret)
+               return ret;
 
        /* Fans */
-       pmbus_add_fan_attributes(client, data);
+       ret = pmbus_add_fan_attributes(client, data);
+       return ret;
 }
 
 /*
@@ -1672,127 +1671,119 @@ static int pmbus_identify_common(struct i2c_client *client,
                }
        }
 
-       /* Determine maximum number of sensors, booleans, and labels */
-       pmbus_find_max_attr(client, data);
        pmbus_clear_fault_page(client, 0);
        return 0;
 }
 
-int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
-                  struct pmbus_driver_info *info)
+static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
+                            struct pmbus_driver_info *info)
 {
-       const struct pmbus_platform_data *pdata = client->dev.platform_data;
-       struct pmbus_data *data;
+       struct device *dev = &client->dev;
        int ret;
 
-       if (!info) {
-               dev_err(&client->dev, "Missing chip information");
-               return -ENODEV;
-       }
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
-                                    | I2C_FUNC_SMBUS_BYTE_DATA
-                                    | I2C_FUNC_SMBUS_WORD_DATA))
-               return -ENODEV;
-
-       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&client->dev, "No memory to allocate driver data\n");
-               return -ENOMEM;
-       }
-
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       /* Bail out if PMBus status register does not exist. */
-       if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
-               dev_err(&client->dev, "PMBus status register not found\n");
-               return -ENODEV;
+       /*
+        * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try
+        * to use PMBUS_STATUS_WORD instead if that is the case.
+        * Bail out if both registers are not supported.
+        */
+       data->status_register = PMBUS_STATUS_BYTE;
+       ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
+       if (ret < 0 || ret == 0xff) {
+               data->status_register = PMBUS_STATUS_WORD;
+               ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD);
+               if (ret < 0 || ret == 0xffff) {
+                       dev_err(dev, "PMBus status register not found\n");
+                       return -ENODEV;
+               }
        }
 
-       if (pdata)
-               data->flags = pdata->flags;
-       data->info = info;
-
        pmbus_clear_faults(client);
 
        if (info->identify) {
                ret = (*info->identify)(client, info);
                if (ret < 0) {
-                       dev_err(&client->dev, "Chip identification failed\n");
+                       dev_err(dev, "Chip identification failed\n");
                        return ret;
                }
        }
 
        if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
-               dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
-                       info->pages);
+               dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages);
                return -ENODEV;
        }
 
        ret = pmbus_identify_common(client, data);
        if (ret < 0) {
-               dev_err(&client->dev, "Failed to identify chip capabilities\n");
+               dev_err(dev, "Failed to identify chip capabilities\n");
                return ret;
        }
+       return 0;
+}
 
-       ret = -ENOMEM;
-       data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor)
-                                    * data->max_sensors, GFP_KERNEL);
-       if (!data->sensors) {
-               dev_err(&client->dev, "No memory to allocate sensor data\n");
-               return -ENOMEM;
-       }
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+                  struct pmbus_driver_info *info)
+{
+       struct device *dev = &client->dev;
+       const struct pmbus_platform_data *pdata = dev->platform_data;
+       struct pmbus_data *data;
+       int ret;
 
-       data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean)
-                                * data->max_booleans, GFP_KERNEL);
-       if (!data->booleans) {
-               dev_err(&client->dev, "No memory to allocate boolean data\n");
-               return -ENOMEM;
-       }
+       if (!info)
+               return -ENODEV;
 
-       data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label)
-                                   * data->max_labels, GFP_KERNEL);
-       if (!data->labels) {
-               dev_err(&client->dev, "No memory to allocate label data\n");
-               return -ENOMEM;
-       }
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+                                    | I2C_FUNC_SMBUS_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
 
-       data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *)
-                                       * data->max_attributes, GFP_KERNEL);
-       if (!data->attributes) {
-               dev_err(&client->dev, "No memory to allocate attribute data\n");
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
                return -ENOMEM;
-       }
 
-       pmbus_find_attributes(client, data);
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+       data->dev = dev;
+
+       if (pdata)
+               data->flags = pdata->flags;
+       data->info = info;
+
+       ret = pmbus_init_common(client, data, info);
+       if (ret < 0)
+               return ret;
+
+       ret = pmbus_find_attributes(client, data);
+       if (ret)
+               goto out_kfree;
 
        /*
         * If there are no attributes, something is wrong.
         * Bail out instead of trying to register nothing.
         */
        if (!data->num_attributes) {
-               dev_err(&client->dev, "No attributes found\n");
-               return -ENODEV;
+               dev_err(dev, "No attributes found\n");
+               ret = -ENODEV;
+               goto out_kfree;
        }
 
        /* Register sysfs hooks */
-       data->group.attrs = data->attributes;
-       ret = sysfs_create_group(&client->dev.kobj, &data->group);
+       ret = sysfs_create_group(&dev->kobj, &data->group);
        if (ret) {
-               dev_err(&client->dev, "Failed to create sysfs entries\n");
-               return ret;
+               dev_err(dev, "Failed to create sysfs entries\n");
+               goto out_kfree;
        }
-       data->hwmon_dev = hwmon_device_register(&client->dev);
+       data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
                ret = PTR_ERR(data->hwmon_dev);
-               dev_err(&client->dev, "Failed to register hwmon device\n");
+               dev_err(dev, "Failed to register hwmon device\n");
                goto out_hwmon_device_register;
        }
        return 0;
 
 out_hwmon_device_register:
-       sysfs_remove_group(&client->dev.kobj, &data->group);
+       sysfs_remove_group(&dev->kobj, &data->group);
+out_kfree:
+       kfree(data->group.attrs);
        return ret;
 }
 EXPORT_SYMBOL_GPL(pmbus_do_probe);
@@ -1802,6 +1793,7 @@ int pmbus_do_remove(struct i2c_client *client)
        struct pmbus_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &data->group);
+       kfree(data->group.attrs);
        return 0;
 }
 EXPORT_SYMBOL_GPL(pmbus_do_remove);
index fc5eed8e85bb94f6e703a50dfe6bcf814353a801..8196441212592d14a6cd49cacc041443918321c9 100644 (file)
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for ZL6100 and compatibles
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -45,12 +46,87 @@ struct zl6100_data {
 
 #define ZL6100_MFR_XTEMP_ENABLE                (1 << 7)
 
+#define MFR_VMON_OV_FAULT_LIMIT                0xf5
+#define MFR_VMON_UV_FAULT_LIMIT                0xf6
+#define MFR_READ_VMON                  0xf7
+
+#define VMON_UV_WARNING                        (1 << 5)
+#define VMON_OV_WARNING                        (1 << 4)
+#define VMON_UV_FAULT                  (1 << 1)
+#define VMON_OV_FAULT                  (1 << 0)
+
 #define ZL6100_WAIT_TIME               1000    /* uS   */
 
 static ushort delay = ZL6100_WAIT_TIME;
 module_param(delay, ushort, 0644);
 MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
 
+/* Convert linear sensor value to milli-units */
+static long zl6100_l2d(s16 l)
+{
+       s16 exponent;
+       s32 mantissa;
+       long val;
+
+       exponent = l >> 11;
+       mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
+
+       val = mantissa;
+
+       /* scale result to milli-units */
+       val = val * 1000L;
+
+       if (exponent >= 0)
+               val <<= exponent;
+       else
+               val >>= -exponent;
+
+       return val;
+}
+
+#define MAX_MANTISSA   (1023 * 1000)
+#define MIN_MANTISSA   (511 * 1000)
+
+static u16 zl6100_d2l(long val)
+{
+       s16 exponent = 0, mantissa;
+       bool negative = false;
+
+       /* simple case */
+       if (val == 0)
+               return 0;
+
+       if (val < 0) {
+               negative = true;
+               val = -val;
+       }
+
+       /* Reduce large mantissa until it fits into 10 bit */
+       while (val >= MAX_MANTISSA && exponent < 15) {
+               exponent++;
+               val >>= 1;
+       }
+       /* Increase small mantissa to improve precision */
+       while (val < MIN_MANTISSA && exponent > -15) {
+               exponent--;
+               val <<= 1;
+       }
+
+       /* Convert mantissa from milli-units to units */
+       mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+       /* Ensure that resulting number is within range */
+       if (mantissa > 0x3ff)
+               mantissa = 0x3ff;
+
+       /* restore sign */
+       if (negative)
+               mantissa = -mantissa;
+
+       /* Convert to 5 bit exponent, 11 bit mantissa */
+       return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
 /* Some chips need a delay between accesses */
 static inline void zl6100_wait(const struct zl6100_data *data)
 {
@@ -65,9 +141,9 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct zl6100_data *data = to_zl6100_data(info);
-       int ret;
+       int ret, vreg;
 
-       if (page || reg >= PMBUS_VIRT_BASE)
+       if (page > 0)
                return -ENXIO;
 
        if (data->id == zl2005) {
@@ -83,9 +159,39 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
                }
        }
 
+       switch (reg) {
+       case PMBUS_VIRT_READ_VMON:
+               vreg = MFR_READ_VMON;
+               break;
+       case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+       case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+               vreg = MFR_VMON_OV_FAULT_LIMIT;
+               break;
+       case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+       case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+               vreg = MFR_VMON_UV_FAULT_LIMIT;
+               break;
+       default:
+               if (reg >= PMBUS_VIRT_BASE)
+                       return -ENXIO;
+               vreg = reg;
+               break;
+       }
+
        zl6100_wait(data);
-       ret = pmbus_read_word_data(client, page, reg);
+       ret = pmbus_read_word_data(client, page, vreg);
        data->access = ktime_get();
+       if (ret < 0)
+               return ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+               ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
+               break;
+       case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+               ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
+               break;
+       }
 
        return ret;
 }
@@ -94,13 +200,35 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct zl6100_data *data = to_zl6100_data(info);
-       int ret;
+       int ret, status;
 
        if (page > 0)
                return -ENXIO;
 
        zl6100_wait(data);
-       ret = pmbus_read_byte_data(client, page, reg);
+
+       switch (reg) {
+       case PMBUS_VIRT_STATUS_VMON:
+               ret = pmbus_read_byte_data(client, 0,
+                                          PMBUS_STATUS_MFR_SPECIFIC);
+               if (ret < 0)
+                       break;
+
+               status = 0;
+               if (ret & VMON_UV_WARNING)
+                       status |= PB_VOLTAGE_UV_WARNING;
+               if (ret & VMON_OV_WARNING)
+                       status |= PB_VOLTAGE_OV_WARNING;
+               if (ret & VMON_UV_FAULT)
+                       status |= PB_VOLTAGE_UV_FAULT;
+               if (ret & VMON_OV_FAULT)
+                       status |= PB_VOLTAGE_OV_FAULT;
+               ret = status;
+               break;
+       default:
+               ret = pmbus_read_byte_data(client, page, reg);
+               break;
+       }
        data->access = ktime_get();
 
        return ret;
@@ -111,13 +239,38 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct zl6100_data *data = to_zl6100_data(info);
-       int ret;
+       int ret, vreg;
 
-       if (page || reg >= PMBUS_VIRT_BASE)
+       if (page > 0)
                return -ENXIO;
 
+       switch (reg) {
+       case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+               word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
+               vreg = MFR_VMON_OV_FAULT_LIMIT;
+               pmbus_clear_cache(client);
+               break;
+       case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+               vreg = MFR_VMON_OV_FAULT_LIMIT;
+               pmbus_clear_cache(client);
+               break;
+       case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+               word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
+               vreg = MFR_VMON_UV_FAULT_LIMIT;
+               pmbus_clear_cache(client);
+               break;
+       case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+               vreg = MFR_VMON_UV_FAULT_LIMIT;
+               pmbus_clear_cache(client);
+               break;
+       default:
+               if (reg >= PMBUS_VIRT_BASE)
+                       return -ENXIO;
+               vreg = reg;
+       }
+
        zl6100_wait(data);
-       ret = pmbus_write_word_data(client, page, reg, word);
+       ret = pmbus_write_word_data(client, page, vreg, word);
        data->access = ktime_get();
 
        return ret;
@@ -225,6 +378,13 @@ static int zl6100_probe(struct i2c_client *client,
          | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
          | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
+       /*
+        * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
+        * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+        */
+       if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+               info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
+
        ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
        if (ret < 0)
                return ret;
index 1c85d39df171670a4727cb95484d3cd5acbf5721..bfe326e896dfd6d277ed22aec18ff9431ae8b8c1 100644 (file)
@@ -139,12 +139,12 @@ static const u8 sht15_crc8_table[] = {
  * @reg:               associated regulator (if specified).
  * @nb:                        notifier block to handle notifications of voltage
  *                      changes.
- * @supply_uV:         local copy of supply voltage used to allow use of
+ * @supply_uv:         local copy of supply voltage used to allow use of
  *                      regulator consumer if available.
- * @supply_uV_valid:   indicates that an updated value has not yet been
+ * @supply_uv_valid:   indicates that an updated value has not yet been
  *                     obtained from the regulator and so any calculations
  *                     based upon it will be invalid.
- * @update_supply_work:        work struct that is used to update the supply_uV.
+ * @update_supply_work:        work struct that is used to update the supply_uv.
  * @interrupt_handled: flag used to indicate a handler has been scheduled.
  */
 struct sht15_data {
@@ -166,8 +166,8 @@ struct sht15_data {
        struct device                   *hwmon_dev;
        struct regulator                *reg;
        struct notifier_block           nb;
-       int                             supply_uV;
-       bool                            supply_uV_valid;
+       int                             supply_uv;
+       bool                            supply_uv_valid;
        struct work_struct              update_supply_work;
        atomic_t                        interrupt_handled;
 };
@@ -212,11 +212,13 @@ static u8 sht15_crc8(struct sht15_data *data,
  *
  * This implements section 3.4 of the data sheet
  */
-static void sht15_connection_reset(struct sht15_data *data)
+static int sht15_connection_reset(struct sht15_data *data)
 {
-       int i;
+       int i, err;
 
-       gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       if (err)
+               return err;
        ndelay(SHT15_TSCKL);
        gpio_set_value(data->pdata->gpio_sck, 0);
        ndelay(SHT15_TSCKL);
@@ -226,6 +228,7 @@ static void sht15_connection_reset(struct sht15_data *data)
                gpio_set_value(data->pdata->gpio_sck, 0);
                ndelay(SHT15_TSCKL);
        }
+       return 0;
 }
 
 /**
@@ -251,10 +254,14 @@ static inline void sht15_send_bit(struct sht15_data *data, int val)
  * conservative ones used in implementation. This implements
  * figure 12 on the data sheet.
  */
-static void sht15_transmission_start(struct sht15_data *data)
+static int sht15_transmission_start(struct sht15_data *data)
 {
+       int err;
+
        /* ensure data is high and output */
-       gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       if (err)
+               return err;
        ndelay(SHT15_TSU);
        gpio_set_value(data->pdata->gpio_sck, 0);
        ndelay(SHT15_TSCKL);
@@ -270,6 +277,7 @@ static void sht15_transmission_start(struct sht15_data *data)
        ndelay(SHT15_TSU);
        gpio_set_value(data->pdata->gpio_sck, 0);
        ndelay(SHT15_TSCKL);
+       return 0;
 }
 
 /**
@@ -293,13 +301,19 @@ static void sht15_send_byte(struct sht15_data *data, u8 byte)
  */
 static int sht15_wait_for_response(struct sht15_data *data)
 {
-       gpio_direction_input(data->pdata->gpio_data);
+       int err;
+
+       err = gpio_direction_input(data->pdata->gpio_data);
+       if (err)
+               return err;
        gpio_set_value(data->pdata->gpio_sck, 1);
        ndelay(SHT15_TSCKH);
        if (gpio_get_value(data->pdata->gpio_data)) {
                gpio_set_value(data->pdata->gpio_sck, 0);
                dev_err(data->dev, "Command not acknowledged\n");
-               sht15_connection_reset(data);
+               err = sht15_connection_reset(data);
+               if (err)
+                       return err;
                return -EIO;
        }
        gpio_set_value(data->pdata->gpio_sck, 0);
@@ -317,12 +331,13 @@ static int sht15_wait_for_response(struct sht15_data *data)
  */
 static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
 {
-       int ret = 0;
+       int err;
 
-       sht15_transmission_start(data);
+       err = sht15_transmission_start(data);
+       if (err)
+               return err;
        sht15_send_byte(data, cmd);
-       ret = sht15_wait_for_response(data);
-       return ret;
+       return sht15_wait_for_response(data);
 }
 
 /**
@@ -352,9 +367,13 @@ static int sht15_soft_reset(struct sht15_data *data)
  * Each byte of data is acknowledged by pulling the data line
  * low for one clock pulse.
  */
-static void sht15_ack(struct sht15_data *data)
+static int sht15_ack(struct sht15_data *data)
 {
-       gpio_direction_output(data->pdata->gpio_data, 0);
+       int err;
+
+       err = gpio_direction_output(data->pdata->gpio_data, 0);
+       if (err)
+               return err;
        ndelay(SHT15_TSU);
        gpio_set_value(data->pdata->gpio_sck, 1);
        ndelay(SHT15_TSU);
@@ -362,7 +381,7 @@ static void sht15_ack(struct sht15_data *data)
        ndelay(SHT15_TSU);
        gpio_set_value(data->pdata->gpio_data, 1);
 
-       gpio_direction_input(data->pdata->gpio_data);
+       return gpio_direction_input(data->pdata->gpio_data);
 }
 
 /**
@@ -371,14 +390,19 @@ static void sht15_ack(struct sht15_data *data)
  *
  * This is basically a NAK (single clock pulse, data high).
  */
-static void sht15_end_transmission(struct sht15_data *data)
+static int sht15_end_transmission(struct sht15_data *data)
 {
-       gpio_direction_output(data->pdata->gpio_data, 1);
+       int err;
+
+       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       if (err)
+               return err;
        ndelay(SHT15_TSU);
        gpio_set_value(data->pdata->gpio_sck, 1);
        ndelay(SHT15_TSCKH);
        gpio_set_value(data->pdata->gpio_sck, 0);
        ndelay(SHT15_TSCKL);
+       return 0;
 }
 
 /**
@@ -410,17 +434,19 @@ static u8 sht15_read_byte(struct sht15_data *data)
  */
 static int sht15_send_status(struct sht15_data *data, u8 status)
 {
-       int ret;
-
-       ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
-       if (ret)
-               return ret;
-       gpio_direction_output(data->pdata->gpio_data, 1);
+       int err;
+
+       err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+       if (err)
+               return err;
+       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       if (err)
+               return err;
        ndelay(SHT15_TSU);
        sht15_send_byte(data, status);
-       ret = sht15_wait_for_response(data);
-       if (ret)
-               return ret;
+       err = sht15_wait_for_response(data);
+       if (err)
+               return err;
 
        data->val_status = status;
        return 0;
@@ -446,7 +472,7 @@ static int sht15_update_status(struct sht15_data *data)
                        || !data->status_valid) {
                ret = sht15_send_cmd(data, SHT15_READ_STATUS);
                if (ret)
-                       goto error_ret;
+                       goto unlock;
                status = sht15_read_byte(data);
 
                if (data->checksumming) {
@@ -458,7 +484,9 @@ static int sht15_update_status(struct sht15_data *data)
                                        == dev_checksum);
                }
 
-               sht15_end_transmission(data);
+               ret = sht15_end_transmission(data);
+               if (ret)
+                       goto unlock;
 
                /*
                 * Perform checksum validation on the received data.
@@ -469,27 +497,27 @@ static int sht15_update_status(struct sht15_data *data)
                        previous_config = data->val_status & 0x07;
                        ret = sht15_soft_reset(data);
                        if (ret)
-                               goto error_ret;
+                               goto unlock;
                        if (previous_config) {
                                ret = sht15_send_status(data, previous_config);
                                if (ret) {
                                        dev_err(data->dev,
                                                "CRC validation failed, unable "
                                                "to restore device settings\n");
-                                       goto error_ret;
+                                       goto unlock;
                                }
                        }
                        ret = -EAGAIN;
-                       goto error_ret;
+                       goto unlock;
                }
 
                data->val_status = status;
                data->status_valid = true;
                data->last_status = jiffies;
        }
-error_ret:
-       mutex_unlock(&data->read_lock);
 
+unlock:
+       mutex_unlock(&data->read_lock);
        return ret;
 }
 
@@ -511,7 +539,9 @@ static int sht15_measurement(struct sht15_data *data,
        if (ret)
                return ret;
 
-       gpio_direction_input(data->pdata->gpio_data);
+       ret = gpio_direction_input(data->pdata->gpio_data);
+       if (ret)
+               return ret;
        atomic_set(&data->interrupt_handled, 0);
 
        enable_irq(gpio_to_irq(data->pdata->gpio_data));
@@ -524,9 +554,14 @@ static int sht15_measurement(struct sht15_data *data,
        ret = wait_event_timeout(data->wait_queue,
                                 (data->state == SHT15_READING_NOTHING),
                                 msecs_to_jiffies(timeout_msecs));
-       if (ret == 0) {/* timeout occurred */
+       if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */
+               data->state = SHT15_READING_NOTHING;
+               return -EIO;
+       } else if (ret == 0) { /* timeout occurred */
                disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
-               sht15_connection_reset(data);
+               ret = sht15_connection_reset(data);
+               if (ret)
+                       return ret;
                return -ETIME;
        }
 
@@ -570,17 +605,17 @@ static int sht15_update_measurements(struct sht15_data *data)
                data->state = SHT15_READING_HUMID;
                ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
                if (ret)
-                       goto error_ret;
+                       goto unlock;
                data->state = SHT15_READING_TEMP;
                ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
                if (ret)
-                       goto error_ret;
+                       goto unlock;
                data->measurements_valid = true;
                data->last_measurement = jiffies;
        }
-error_ret:
-       mutex_unlock(&data->read_lock);
 
+unlock:
+       mutex_unlock(&data->read_lock);
        return ret;
 }
 
@@ -598,8 +633,8 @@ static inline int sht15_calc_temp(struct sht15_data *data)
 
        for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
                /* Find pointer to interpolate */
-               if (data->supply_uV > temppoints[i - 1].vdd) {
-                       d1 = (data->supply_uV - temppoints[i - 1].vdd)
+               if (data->supply_uv > temppoints[i - 1].vdd) {
+                       d1 = (data->supply_uv - temppoints[i - 1].vdd)
                                * (temppoints[i].d1 - temppoints[i - 1].d1)
                                / (temppoints[i].vdd - temppoints[i - 1].vdd)
                                + temppoints[i - 1].d1;
@@ -818,7 +853,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
        /* Read the data back from the device */
        val = sht15_read_byte(data);
        val <<= 8;
-       sht15_ack(data);
+       if (sht15_ack(data))
+               goto wakeup;
        val |= sht15_read_byte(data);
 
        if (data->checksumming) {
@@ -826,7 +862,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
                 * Ask the device for a checksum and read it back.
                 * Note: the device sends the checksum byte reversed.
                 */
-               sht15_ack(data);
+               if (sht15_ack(data))
+                       goto wakeup;
                dev_checksum = sht15_reverse(sht15_read_byte(data));
                checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
                        SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
@@ -837,7 +874,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
        }
 
        /* Tell the device we are done */
-       sht15_end_transmission(data);
+       if (sht15_end_transmission(data))
+               goto wakeup;
 
        switch (data->state) {
        case SHT15_READING_TEMP:
@@ -851,6 +889,7 @@ static void sht15_bh_read_data(struct work_struct *work_s)
        }
 
        data->state = SHT15_READING_NOTHING;
+wakeup:
        wake_up(&data->wait_queue);
 }
 
@@ -859,7 +898,7 @@ static void sht15_update_voltage(struct work_struct *work_s)
        struct sht15_data *data
                = container_of(work_s, struct sht15_data,
                               update_supply_work);
-       data->supply_uV = regulator_get_voltage(data->reg);
+       data->supply_uv = regulator_get_voltage(data->reg);
 }
 
 /**
@@ -878,7 +917,7 @@ static int sht15_invalidate_voltage(struct notifier_block *nb,
        struct sht15_data *data = container_of(nb, struct sht15_data, nb);
 
        if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
-               data->supply_uV_valid = false;
+               data->supply_uv_valid = false;
        schedule_work(&data->update_supply_work);
 
        return NOTIFY_OK;
@@ -906,7 +945,7 @@ static int sht15_probe(struct platform_device *pdev)
                return -EINVAL;
        }
        data->pdata = pdev->dev.platform_data;
-       data->supply_uV = data->pdata->supply_mv * 1000;
+       data->supply_uv = data->pdata->supply_mv * 1000;
        if (data->pdata->checksum)
                data->checksumming = true;
        if (data->pdata->no_otp_reload)
@@ -924,7 +963,7 @@ static int sht15_probe(struct platform_device *pdev)
 
                voltage = regulator_get_voltage(data->reg);
                if (voltage)
-                       data->supply_uV = voltage;
+                       data->supply_uv = voltage;
 
                regulator_enable(data->reg);
                /*
@@ -942,17 +981,17 @@ static int sht15_probe(struct platform_device *pdev)
        }
 
        /* Try requesting the GPIOs */
-       ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
+       ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
+                       GPIOF_OUT_INIT_LOW, "SHT15 sck");
        if (ret) {
-               dev_err(&pdev->dev, "gpio request failed\n");
+               dev_err(&pdev->dev, "clock line GPIO request failed\n");
                goto err_release_reg;
        }
-       gpio_direction_output(data->pdata->gpio_sck, 0);
 
        ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
                                "SHT15 data");
        if (ret) {
-               dev_err(&pdev->dev, "gpio request failed\n");
+               dev_err(&pdev->dev, "data line GPIO request failed\n");
                goto err_release_reg;
        }
 
@@ -966,7 +1005,9 @@ static int sht15_probe(struct platform_device *pdev)
                goto err_release_reg;
        }
        disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
-       sht15_connection_reset(data);
+       ret = sht15_connection_reset(data);
+       if (ret)
+               goto err_release_reg;
        ret = sht15_soft_reset(data);
        if (ret)
                goto err_release_reg;
index 06ce3c911db9bbc1bdc1169ec420a79b3b818f55..c35847a1a0a32c27c8d2aa1d87c6c179ed13f91e 100644 (file)
@@ -132,7 +132,7 @@ static struct platform_device *pdev;
  */
 static inline u8 IN_TO_REG(unsigned long val)
 {
-       unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+       unsigned long nval = clamp_val(val, 0, 4080);
        return (nval + 8) / 16;
 }
 #define IN_FROM_REG(val) ((val) *  16)
@@ -141,7 +141,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 {
        if (rpm <= 0)
                return 255;
-       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+       return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline int FAN_FROM_REG(u8 val, int div)
@@ -159,7 +159,7 @@ static inline int TEMP_FROM_REG(s8 val)
 }
 static inline s8 TEMP_TO_REG(int val)
 {
-       int nval = SENSORS_LIMIT(val, -54120, 157530) ;
+       int nval = clamp_val(val, -54120, 157530) ;
        return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
 }
 
index dba0c567e7a1a730f60f2ffaff6012a12d7df3dd..6d8255ccf07afb1a9d31955f82e91392a824a4ba 100644 (file)
@@ -326,7 +326,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute
        /* Preserve fan min */
        tmp = 192 - (old_div * (192 - data->fan_preload[nr])
                     + new_div / 2) / new_div;
-       data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
+       data->fan_preload[nr] = clamp_val(tmp, 0, 191);
        smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
                             data->fan_preload[nr]);
        mutex_unlock(&data->update_lock);
index 36a3478d0799eba500ec7242c5533314022aebaf..efee4c59239fcff8aa7b675c01cb5b9ac6bab5bd 100644 (file)
@@ -77,7 +77,7 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n)
 
 static inline u8 IN_TO_REG(unsigned long val, int n)
 {
-       return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+       return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
 }
 
 /*
@@ -86,7 +86,7 @@ static inline u8 IN_TO_REG(unsigned long val, int n)
  */
 static inline s8 TEMP_TO_REG(int val)
 {
-       return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
+       return clamp_val(SCALE(val, 1, 1000), -128000, 127000);
 }
 
 static inline int TEMP_FROM_REG(s8 val)
index 3c2c48d904e658736605ee95e5b21f08cd1ccf98..4b59eb53b18ac38ccaeb949f9feab2ba3fdc097e 100644 (file)
@@ -134,7 +134,7 @@ static ssize_t set_analog_out(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
+       data->analog_out = clamp_val(tmp, 0, 255);
        i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
                                  data->analog_out);
 
@@ -187,7 +187,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+       data->temp_min[nr] = clamp_val(val / 1000, -128, 127);
        i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
                                  data->temp_min[nr]);
        mutex_unlock(&data->update_lock);
@@ -216,7 +216,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+       data->temp_max[nr] = clamp_val(val / 1000, -128, 127);
        i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
                                  data->temp_max[nr]);
        mutex_unlock(&data->update_lock);
index b10c3d36ccbc3b8b77410701b763b2890ed5467d..523dd89ba498c3dff27cbe87677fb8d2095c39c0 100644 (file)
@@ -115,7 +115,7 @@ static ssize_t tmp102_set_temp(struct device *dev,
 
        if (kstrtol(buf, 10, &val) < 0)
                return -EINVAL;
-       val = SENSORS_LIMIT(val, -256000, 255000);
+       val = clamp_val(val, -256000, 255000);
 
        mutex_lock(&tmp102->lock);
        tmp102->temp[sda->index] = val;
index e6205487516480ddfbd56acd3adf2828b45f9c74..c85f6967ccc34534da241368af7a440d267bf6bf 100644 (file)
@@ -142,10 +142,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
 static u16 tmp401_temp_to_register(long temp, u8 config)
 {
        if (config & TMP401_CONFIG_RANGE) {
-               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp = clamp_val(temp, -64000, 191000);
                temp += 64000;
        } else
-               temp = SENSORS_LIMIT(temp, 0, 127000);
+               temp = clamp_val(temp, 0, 127000);
 
        return (temp * 160 + 312) / 625;
 }
@@ -163,10 +163,10 @@ static int tmp401_crit_register_to_temp(u8 reg, u8 config)
 static u8 tmp401_crit_temp_to_register(long temp, u8 config)
 {
        if (config & TMP401_CONFIG_RANGE) {
-               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp = clamp_val(temp, -64000, 191000);
                temp += 64000;
        } else
-               temp = SENSORS_LIMIT(temp, 0, 127000);
+               temp = clamp_val(temp, 0, 127000);
 
        return (temp + 500) / 1000;
 }