Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/staging:
  hwmon: (coretemp) Fix checkpatch errors
  hwmon: Remove pkgtemp driver
  hwmon: (coretemp) Merge pkgtemp with coretemp
  hwmon: (pmbus) Add support for Analog Devices ADM1275
  hwmon: (pmbus) Support for TI UCD90xxx series Sequencer and System Health Controllers
  hwmon: (pmbus) Add support for TI UCD9200 series of PWM System Controllers
  hwmon: (pmbus) Use device specific function to read fan configuration
  hwmon: (pmbus) Expand scope of device specific get_status function
  hwmon: (pmbus) Introduce infrastructure to detect sensors and limit registers
  hwmon: Driver for MAX16065 System Manager and compatibles
  hwmon: (sht15) add support for CRC validation
  hwmon: (sht15) add support for the status register
  hwmon: (sht15) clean-up the probe function
  hwmon: (sht15) general code clean-up
  hwmon: Add support for MAX6642
diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275
new file mode 100644
index 0000000..6a3a647
--- /dev/null
+++ b/Documentation/hwmon/adm1275
@@ -0,0 +1,60 @@
+Kernel driver adm1275
+=====================
+
+Supported chips:
+  * Analog Devices ADM1275
+    Prefix: 'adm1275'
+    Addresses scanned: -
+    Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Analog Devices ADM1275 Hot-Swap
+Controller and Digital Power Monitor.
+
+The ADM1275 is a hot-swap controller that allows a circuit board to be removed
+from or inserted into a live backplane. It also features current and voltage
+readback via an integrated 12-bit analog-to-digital converter (ADC), accessed
+using a PMBus. interface.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label		"vin1" or "vout1" depending on chip variant and
+			configuration.
+in1_input		Measured voltage. From READ_VOUT register.
+in1_min			Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in1_max			Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in1_min_alarm		Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in1_max_alarm		Voltage high alarm. From VOLTAGE_OV_WARNING status.
+
+curr1_label		"iout1"
+curr1_input		Measured current. From READ_IOUT register.
+curr1_max		Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr1_max_alarm		Current high alarm. From IOUT_OC_WARN_LIMIT register.
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index 25568f8..f85e913 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -15,8 +15,13 @@
 
 Description
 -----------
+This driver permits reading the DTS (Digital Temperature Sensor) embedded
+inside Intel CPUs. This driver can read both the per-core and per-package
+temperature using the appropriate sensors. The per-package sensor is new;
+as of now, it is present only in the SandyBridge platform. The driver will
+show the temperature of all cores inside a package under a single device
+directory inside hwmon.
 
-This driver permits reading temperature sensor embedded inside Intel Core CPU.
 Temperature is measured in degrees Celsius and measurement resolution is
 1 degree C. Valid temperatures are from 0 to TjMax degrees C, because
 the actual value of temperature register is in fact a delta from TjMax.
@@ -27,13 +32,15 @@
 may be raised, if the temperature grows enough (more than TjMax) to trigger
 the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
 
-temp1_input	 - Core temperature (in millidegrees Celsius).
-temp1_max	 - All cooling devices should be turned on (on Core2).
-temp1_crit	 - Maximum junction temperature (in millidegrees Celsius).
-temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
+All Sysfs entries are named with their core_id (represented here by 'X').
+tempX_input	 - Core temperature (in millidegrees Celsius).
+tempX_max	 - All cooling devices should be turned on (on Core2).
+tempX_crit	 - Maximum junction temperature (in millidegrees Celsius).
+tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
 		   Correct CPU operation is no longer guaranteed.
-temp1_label	 - Contains string "Core X", where X is processor
-		   number.
+tempX_label	 - Contains string "Core X", where X is processor
+		   number. For Package temp, this will be "Physical id Y",
+		   where Y is the package number.
 
 The TjMax temperature is set to 85 degrees C if undocumented model specific
 register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
diff --git a/Documentation/hwmon/max16065 b/Documentation/hwmon/max16065
new file mode 100644
index 0000000..44b4f61
--- /dev/null
+++ b/Documentation/hwmon/max16065
@@ -0,0 +1,98 @@
+Kernel driver max16065
+======================
+
+Supported chips:
+  * Maxim MAX16065, MAX16066
+    Prefixes: 'max16065', 'max16066'
+    Addresses scanned: -
+    Datasheet:
+	http://datasheets.maxim-ic.com/en/ds/MAX16065-MAX16066.pdf
+ *  Maxim MAX16067
+    Prefix: 'max16067'
+    Addresses scanned: -
+    Datasheet:
+	http://datasheets.maxim-ic.com/en/ds/MAX16067.pdf
+ *  Maxim MAX16068
+    Prefix: 'max16068'
+    Addresses scanned: -
+    Datasheet:
+	http://datasheets.maxim-ic.com/en/ds/MAX16068.pdf
+ *  Maxim MAX16070/MAX16071
+    Prefixes: 'max16070', 'max16071'
+    Addresses scanned: -
+    Datasheet:
+	http://datasheets.maxim-ic.com/en/ds/MAX16070-MAX16071.pdf
+
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+[From datasheets] The MAX16065/MAX16066 flash-configurable system managers
+monitor and sequence multiple system voltages. The MAX16065/MAX16066 can also
+accurately monitor (+/-2.5%) one current channel using a dedicated high-side
+current-sense amplifier. The MAX16065 manages up to twelve system voltages
+simultaneously, and the MAX16066 manages up to eight supply voltages.
+
+The MAX16067 flash-configurable system manager monitors and sequences multiple
+system voltages. The MAX16067 manages up to six system voltages simultaneously.
+
+The MAX16068 flash-configurable system manager monitors and manages up to six
+system voltages simultaneously.
+
+The MAX16070/MAX16071 flash-configurable system monitors supervise multiple
+system voltages. The MAX16070/MAX16071 can also accurately monitor (+/-2.5%)
+one current channel using a dedicated high-side current-sense amplifier. The
+MAX16070 monitors up to twelve system voltages simultaneously, and the MAX16071
+monitors up to eight supply voltages.
+
+Each monitored channel has its own low and high critical limits. MAX16065,
+MAX16066, MAX16070, and MAX16071 support an additional limit which is
+configurable as either low or high secondary limit. MAX16065, MAX16066,
+MAX16070, and MAX16071 also support supply current monitoring.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for devices, since there is no register which
+can be safely used to identify the chip. You will have to instantiate
+the devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Sysfs entries
+-------------
+
+in[0-11]_input		Input voltage measurements.
+
+in12_input		Voltage on CSP (Current Sense Positive) pin.
+			Only if the chip supports current sensing and if
+			current sensing is enabled.
+
+in[0-11]_min		Low warning limit.
+			Supported on MAX16065, MAX16066, MAX16070, and MAX16071
+			only.
+
+in[0-11]_max		High warning limit.
+			Supported on MAX16065, MAX16066, MAX16070, and MAX16071
+			only.
+
+			Either low or high warning limits are supported
+			(depending on chip configuration), but not both.
+
+in[0-11]_lcrit		Low critical limit.
+
+in[0-11]_crit		High critical limit.
+
+in[0-11]_alarm		Input voltage alarm.
+
+curr1_input		Current sense input; only if the chip supports current
+			sensing and if current sensing is enabled.
+			Displayed current assumes 0.001 Ohm current sense
+			resistor.
+
+curr1_alarm		Overcurrent alarm; only if the chip supports current
+			sensing and if current sensing is enabled.
diff --git a/Documentation/hwmon/max6642 b/Documentation/hwmon/max6642
new file mode 100644
index 0000000..afbd3e4
--- /dev/null
+++ b/Documentation/hwmon/max6642
@@ -0,0 +1,21 @@
+Kernel driver max6642
+=====================
+
+Supported chips:
+  * Maxim MAX6642
+    Prefix: 'max6642'
+    Addresses scanned: I2C 0x48-0x4f
+    Datasheet: Publicly available at the Maxim website
+               http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
+
+Authors:
+        Per Dalen <per.dalen@appeartv.com>
+
+Description
+-----------
+
+The MAX6642 is a digital temperature sensor. It senses its own temperature as
+well as the temperature on one external diode.
+
+All temperature values are given in degrees Celsius. Resolution
+is 0.25 degree for the local temperature and for the remote temperature.
diff --git a/Documentation/hwmon/pkgtemp b/Documentation/hwmon/pkgtemp
deleted file mode 100644
index c8e1fb0..0000000
--- a/Documentation/hwmon/pkgtemp
+++ /dev/null
@@ -1,36 +0,0 @@
-Kernel driver pkgtemp
-======================
-
-Supported chips:
-  * Intel family
-    Prefix: 'pkgtemp'
-    CPUID:
-    Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
-               Volume 3A: System Programming Guide
-
-Author: Fenghua Yu
-
-Description
------------
-
-This driver permits reading package level temperature sensor embedded inside
-Intel CPU package. The sensors can be in core, uncore, memory controller, or
-other components in a package. The feature is first implemented in Intel Sandy
-Bridge platform.
-
-Temperature is measured in degrees Celsius and measurement resolution is
-1 degree C. Valid temperatures are from 0 to TjMax degrees C, because the actual
-value of temperature register is in fact a delta from TjMax.
-
-Temperature known as TjMax is the maximum junction temperature of package.
-We get this from MSR_IA32_TEMPERATURE_TARGET. If the MSR is not accessible,
-we define TjMax as 100 degrees Celsius. At this temperature, protection
-mechanism will perform actions to forcibly cool down the package. Alarm
-may be raised, if the temperature grows enough (more than TjMax) to trigger
-the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
-
-temp1_input	  - Package temperature (in millidegrees Celsius).
-temp1_max        - All cooling devices should be turned on.
-temp1_crit	  - Maximum junction temperature (in millidegrees Celsius).
-temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
-		    Correct CPU operation is no longer guaranteed.
diff --git a/Documentation/hwmon/sht15 b/Documentation/hwmon/sht15
new file mode 100644
index 0000000..02850bd
--- /dev/null
+++ b/Documentation/hwmon/sht15
@@ -0,0 +1,74 @@
+Kernel driver sht15
+===================
+
+Authors:
+  * Wouter Horre
+  * Jonathan Cameron
+  * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+  * Jerome Oufella <jerome.oufella@savoirfairelinux.com>
+
+Supported chips:
+  * Sensirion SHT10
+    Prefix: 'sht10'
+
+  * Sensirion SHT11
+    Prefix: 'sht11'
+
+  * Sensirion SHT15
+    Prefix: 'sht15'
+
+  * Sensirion SHT71
+    Prefix: 'sht71'
+
+  * Sensirion SHT75
+    Prefix: 'sht75'
+
+Datasheet: Publicly available at the Sensirion website
+http://www.sensirion.ch/en/pdf/product_information/Datasheet-humidity-sensor-SHT1x.pdf
+
+Description
+-----------
+
+The SHT10, SHT11, SHT15, SHT71, and SHT75 are humidity and temperature
+sensors.
+
+The devices communicate using two GPIO lines.
+
+Supported resolutions for the measurements are 14 bits for temperature and 12
+bits for humidity, or 12 bits for temperature and 8 bits for humidity.
+
+The humidity calibration coefficients are programmed into an OTP memory on the
+chip. These coefficients are used to internally calibrate the signals from the
+sensors. Disabling the reload of those coefficients allows saving 10ms for each
+measurement and decrease power consumption, while loosing on precision.
+
+Some options may be set directly in the sht15_platform_data structure
+or via sysfs attributes.
+
+Notes:
+  * The regulator supply name is set to "vcc".
+  * If a CRC validation fails, a soft reset command is sent, which resets
+    status register to its hardware default value, but the driver will try to
+    restore the previous device configuration.
+
+Platform data
+-------------
+
+* checksum:
+  set it to true to enable CRC validation of the readings (default to false).
+* no_otp_reload:
+  flag to indicate not to reload from OTP (default to false).
+* low_resolution:
+  flag to indicate the temp/humidity resolution to use (default to false).
+
+Sysfs interface
+---------------
+
+* temp1_input:     temperature input
+* humidity1_input: humidity input
+* heater_enable:   write 1 in this attribute to enable the on-chip heater,
+                   0 to disable it. Be careful not to enable the heater
+                   for too long.
+* temp1_fault:     if 1, this means that the voltage is low (below 2.47V) and
+                   measurement may be invalid.
+* humidity1_fault: same as temp1_fault.
diff --git a/Documentation/hwmon/ucd9000 b/Documentation/hwmon/ucd9000
new file mode 100644
index 0000000..40ca6db
--- /dev/null
+++ b/Documentation/hwmon/ucd9000
@@ -0,0 +1,110 @@
+Kernel driver ucd9000
+=====================
+
+Supported chips:
+  * TI UCD90120, UCD90124, UCD9090, and UCD90910
+    Prefixes: 'ucd90120', 'ucd90124', 'ucd9090', 'ucd90910'
+    Addresses scanned: -
+    Datasheets:
+	http://focus.ti.com/lit/ds/symlink/ucd90120.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd90124.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9090.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd90910.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+From datasheets:
+
+The UCD90120 Power Supply Sequencer and System Health Monitor monitors and
+sequences up to 12 independent voltage rails. The device integrates a 12-bit
+ADC with a 2.5V internal reference for monitoring up to 13 power supply voltage,
+current, or temperature inputs.
+
+The UCD90124 is a 12-rail PMBus/I2C addressable power-supply sequencer and
+system-health monitor. The device integrates a 12-bit ADC for monitoring up to
+13 power-supply voltage, current, or temperature inputs. Twenty-six GPIO pins
+can be used for power supply enables, power-on reset signals, external
+interrupts, cascading, or other system functions. Twelve of these pins offer PWM
+functionality. Using these pins, the UCD90124 offers support for fan control,
+margining, and general-purpose PWM functions.
+
+The UCD9090 is a 10-rail PMBus/I2C addressable power-supply sequencer and
+monitor. The device integrates a 12-bit ADC for monitoring up to 10 power-supply
+voltage inputs. Twenty-three GPIO pins can be used for power supply enables,
+power-on reset signals, external interrupts, cascading, or other system
+functions. Ten of these pins offer PWM functionality. Using these pins, the
+UCD9090 offers support for margining, and general-purpose PWM functions.
+
+The UCD90910 is a ten-rail I2C / PMBus addressable power-supply sequencer and
+system-health monitor. The device integrates a 12-bit ADC for monitoring up to
+13 power-supply voltage, current, or temperature inputs.
+
+This driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in[1-12]_label		"vout[1-12]".
+in[1-12]_input		Measured voltage. From READ_VOUT register.
+in[1-12]_min		Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[1-12]_max		Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[1-12]_lcrit		Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[1-12]_crit		Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[1-12]_min_alarm	Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[1-12]_max_alarm	Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[1-12]_lcrit_alarm	Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[1-12]_crit_alarm	Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr[1-12]_label	"iout[1-12]".
+curr[1-12]_input	Measured current. From READ_IOUT register.
+curr[1-12]_max		Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr[1-12]_lcrit	Critical minumum output current. From IOUT_UC_FAULT_LIMIT
+			register.
+curr[1-12]_crit		Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr[1-12]_max_alarm	Current high alarm. From IOUT_OC_WARNING status.
+curr[1-12]_crit_alarm	Current critical high alarm. From IOUT_OC_FAULT status.
+
+			For each attribute index, either voltage or current is
+			reported, but not both. If voltage or current is
+			reported depends on the chip configuration.
+
+temp[1-2]_input		Measured temperatures. From READ_TEMPERATURE_1 and
+			READ_TEMPERATURE_2 registers.
+temp[1-2]_max		Maximum temperature. From OT_WARN_LIMIT register.
+temp[1-2]_crit		Critical high temperature. From OT_FAULT_LIMIT register.
+temp[1-2]_max_alarm	Temperature high alarm.
+temp[1-2]_crit_alarm	Temperature critical high alarm.
+
+fan[1-4]_input		Fan RPM.
+fan[1-4]_alarm		Fan alarm.
+fan[1-4]_fault		Fan fault.
+
+			Fan attributes are only available on chips supporting
+			fan control (UCD90124, UCD90910). Attribute files are
+			created only for enabled fans.
+			Note that even though UCD90910 supports up to 10 fans,
+			only up to four fans are currently supported.
diff --git a/Documentation/hwmon/ucd9200 b/Documentation/hwmon/ucd9200
new file mode 100644
index 0000000..3c58607
--- /dev/null
+++ b/Documentation/hwmon/ucd9200
@@ -0,0 +1,112 @@
+Kernel driver ucd9200
+=====================
+
+Supported chips:
+  * TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+    Prefixes: 'ucd9220', 'ucd9222', 'ucd9224', 'ucd9240', 'ucd9244', 'ucd9246',
+	'ucd9248'
+    Addresses scanned: -
+    Datasheets:
+	http://focus.ti.com/lit/ds/symlink/ucd9220.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9222.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9224.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9240.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9244.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9246.pdf
+	http://focus.ti.com/lit/ds/symlink/ucd9248.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+[From datasheets] UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and
+UCD9248 are multi-rail, multi-phase synchronous buck digital PWM controllers
+designed for non-isolated DC/DC power applications. The devices integrate
+dedicated circuitry for DC/DC loop management with flash memory and a serial
+interface to support configuration, monitoring and management.
+
+This driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label		"vin".
+in1_input		Measured voltage. From READ_VIN register.
+in1_min			Minumum Voltage. From VIN_UV_WARN_LIMIT register.
+in1_max			Maximum voltage. From VIN_OV_WARN_LIMIT register.
+in1_lcrit		Critical minumum Voltage. VIN_UV_FAULT_LIMIT register.
+in1_crit		Critical maximum voltage. From VIN_OV_FAULT_LIMIT register.
+in1_min_alarm		Voltage low alarm. From VIN_UV_WARNING status.
+in1_max_alarm		Voltage high alarm. From VIN_OV_WARNING status.
+in1_lcrit_alarm		Voltage critical low alarm. From VIN_UV_FAULT status.
+in1_crit_alarm		Voltage critical high alarm. From VIN_OV_FAULT status.
+
+in[2-5]_label		"vout[1-4]".
+in[2-5]_input		Measured voltage. From READ_VOUT register.
+in[2-5]_min		Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[2-5]_max		Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[2-5]_lcrit		Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[2-5]_crit		Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[2-5]_min_alarm	Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[2-5]_max_alarm	Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[2-5]_lcrit_alarm	Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[2-5]_crit_alarm	Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr1_label		"iin".
+curr1_input		Measured current. From READ_IIN register.
+
+curr[2-5]_label		"iout[1-4]".
+curr[2-5]_input		Measured current. From READ_IOUT register.
+curr[2-5]_max		Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr[2-5]_lcrit		Critical minumum output current. From IOUT_UC_FAULT_LIMIT
+			register.
+curr[2-5]_crit		Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr[2-5]_max_alarm	Current high alarm. From IOUT_OC_WARNING status.
+curr[2-5]_crit_alarm	Current critical high alarm. From IOUT_OC_FAULT status.
+
+power1_input		Measured input power. From READ_PIN register.
+power1_label		"pin"
+
+power[2-5]_input	Measured output power. From READ_POUT register.
+power[2-5]_label	"pout[1-4]"
+
+			The number of output voltage, current, and power
+			attribute sets is determined by the number of enabled
+			rails. See chip datasheets for details.
+
+temp[1-5]_input		Measured temperatures. From READ_TEMPERATURE_1 and
+		        READ_TEMPERATURE_2 registers.
+			temp1 is the chip internal temperature. temp[2-5] are
+			rail temperatures.  temp[2-5] attributes are only
+			created for enabled rails. See chip datasheets for
+			details.
+temp[1-5]_max		Maximum temperature. From OT_WARN_LIMIT register.
+temp[1-5]_crit		Critical high temperature. From OT_FAULT_LIMIT register.
+temp[1-5]_max_alarm	Temperature high alarm.
+temp[1-5]_crit_alarm	Temperature critical high alarm.
+
+fan1_input		Fan RPM. ucd9240 only.
+fan1_alarm		Fan alarm. ucd9240 only.
+fan1_fault		Fan fault. ucd9240 only.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 50e40db..43221be 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -408,13 +408,6 @@
 	  sensor inside your CPU. Most of the family 6 CPUs
 	  are supported. Check Documentation/hwmon/coretemp for details.
 
-config SENSORS_PKGTEMP
-	tristate "Intel processor package temperature sensor"
-	depends on X86 && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the package level temperature
-	  sensor inside your CPU. Check documentation/driver for details.
-
 config SENSORS_IBMAEM
 	tristate "IBM Active Energy Manager temperature/power sensors and control"
 	select IPMI_SI
@@ -708,6 +701,22 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max1111.
 
+config SENSORS_MAX16065
+	tristate "Maxim MAX16065 System Manager and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for hardware monitoring
+	  capabilities of the following Maxim System Manager chips.
+	    MAX16065
+	    MAX16066
+	    MAX16067
+	    MAX16068
+	    MAX16070
+	    MAX16071
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max16065.
+
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
 	depends on I2C
@@ -727,6 +736,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max6639.
 
+config SENSORS_MAX6642
+	tristate "Maxim MAX6642 sensor chip"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for MAX6642 sensor chip.
+	  MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
+	  with Overtemperature Alarm from Maxim.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max6642.
+
 config SENSORS_MAX6650
 	tristate "Maxim MAX6650 sensor chip"
 	depends on I2C && EXPERIMENTAL
@@ -800,6 +820,16 @@
 	  This driver can also be built as a module. If so, the module will
 	  be called pmbus.
 
+config SENSORS_ADM1275
+	tristate "Analog Devices ADM1275"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Analog
+	  Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called adm1275.
+
 config SENSORS_MAX16064
 	tristate "Maxim MAX16064"
 	default n
@@ -830,6 +860,28 @@
 	  This driver can also be built as a module. If so, the module will
 	  be called max8688.
 
+config SENSORS_UCD9000
+	tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for TI
+	  UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
+	  Controllers.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ucd9000.
+
+config SENSORS_UCD9200
+	tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for TI
+	  UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+	  Digital PWM System Controllers.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ucd9200.
+
 endif # PMBUS
 
 config SENSORS_SHT15
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 967d0ea..28e8d52f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -40,7 +40,6 @@
 obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
-obj-$(CONFIG_SENSORS_PKGTEMP)	+= pkgtemp.o
 obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
 obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
@@ -83,8 +82,10 @@
 obj-$(CONFIG_SENSORS_LTC4245)	+= ltc4245.o
 obj-$(CONFIG_SENSORS_LTC4261)	+= ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)	+= max1111.o
+obj-$(CONFIG_SENSORS_MAX16065)	+= max16065.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o
+obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
@@ -118,9 +119,12 @@
 # PMBus drivers
 obj-$(CONFIG_PMBUS)		+= pmbus_core.o
 obj-$(CONFIG_SENSORS_PMBUS)	+= pmbus.o
+obj-$(CONFIG_SENSORS_ADM1275)	+= adm1275.o
 obj-$(CONFIG_SENSORS_MAX16064)	+= max16064.o
 obj-$(CONFIG_SENSORS_MAX34440)	+= max34440.o
 obj-$(CONFIG_SENSORS_MAX8688)	+= max8688.o
+obj-$(CONFIG_SENSORS_UCD9000)	+= ucd9000.o
+obj-$(CONFIG_SENSORS_UCD9200)	+= ucd9200.o
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
 
diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c
new file mode 100644
index 0000000..c2ee204
--- /dev/null
+++ b/drivers/hwmon/adm1275.c
@@ -0,0 +1,121 @@
+/*
+ * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
+ * and Digital Power Monitor
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define ADM1275_PMON_CONFIG		0xd4
+
+#define ADM1275_VIN_VOUT_SELECT		(1 << 6)
+#define ADM1275_VRANGE			(1 << 5)
+
+static int adm1275_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int config;
+	struct pmbus_driver_info *info;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_BYTE_DATA))
+		return -ENODEV;
+
+	info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+	if (config < 0)
+		return config;
+
+	info->pages = 1;
+	info->direct[PSC_VOLTAGE_IN] = true;
+	info->direct[PSC_VOLTAGE_OUT] = true;
+	info->direct[PSC_CURRENT_OUT] = true;
+	info->m[PSC_CURRENT_OUT] = 800;
+	info->b[PSC_CURRENT_OUT] = 20475;
+	info->R[PSC_CURRENT_OUT] = -1;
+	info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+
+	if (config & ADM1275_VRANGE) {
+		info->m[PSC_VOLTAGE_IN] = 19045;
+		info->b[PSC_VOLTAGE_IN] = 0;
+		info->R[PSC_VOLTAGE_IN] = -2;
+		info->m[PSC_VOLTAGE_OUT] = 19045;
+		info->b[PSC_VOLTAGE_OUT] = 0;
+		info->R[PSC_VOLTAGE_OUT] = -2;
+	} else {
+		info->m[PSC_VOLTAGE_IN] = 6666;
+		info->b[PSC_VOLTAGE_IN] = 0;
+		info->R[PSC_VOLTAGE_IN] = -1;
+		info->m[PSC_VOLTAGE_OUT] = 6666;
+		info->b[PSC_VOLTAGE_OUT] = 0;
+		info->R[PSC_VOLTAGE_OUT] = -1;
+	}
+
+	if (config & ADM1275_VIN_VOUT_SELECT)
+		info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+	else
+		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+
+	return pmbus_do_probe(client, id, info);
+}
+
+static int adm1275_remove(struct i2c_client *client)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	int ret;
+
+	ret = pmbus_do_remove(client);
+	kfree(info);
+	return ret;
+}
+
+static const struct i2c_device_id adm1275_id[] = {
+	{"adm1275", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1275_id);
+
+static struct i2c_driver adm1275_driver = {
+	.driver = {
+		   .name = "adm1275",
+		   },
+	.probe = adm1275_probe,
+	.remove = adm1275_remove,
+	.id_table = adm1275_id,
+};
+
+static int __init adm1275_init(void)
+{
+	return i2c_add_driver(&adm1275_driver);
+}
+
+static void __exit adm1275_exit(void)
+{
+	i2c_del_driver(&adm1275_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
+MODULE_LICENSE("GPL");
+module_init(adm1275_init);
+module_exit(adm1275_exit);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 194ca0a..5c7cd60 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -35,128 +35,152 @@
 #include <linux/platform_device.h>
 #include <linux/cpu.h>
 #include <linux/pci.h>
+#include <linux/smp.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
-#include <asm/smp.h>
 
 #define DRVNAME	"coretemp"
 
-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
-		SHOW_NAME } SHOW;
+#define BASE_SYSFS_ATTR_NO	2	/* Sysfs Base attr no for coretemp */
+#define NUM_REAL_CORES		16	/* Number of Real cores per cpu */
+#define CORETEMP_NAME_LENGTH	17	/* String Length of attrs */
+#define MAX_ATTRS		5	/* Maximum no of per-core attrs */
+#define MAX_CORE_DATA		(NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
+
+#ifdef CONFIG_SMP
+#define TO_PHYS_ID(cpu)		cpu_data(cpu).phys_proc_id
+#define TO_CORE_ID(cpu)		cpu_data(cpu).cpu_core_id
+#define TO_ATTR_NO(cpu)		(TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
+#else
+#define TO_PHYS_ID(cpu)		(cpu)
+#define TO_CORE_ID(cpu)		(cpu)
+#define TO_ATTR_NO(cpu)		(cpu)
+#endif
 
 /*
- * Functions declaration
+ * Per-Core Temperature Data
+ * @last_updated: The time when the current temperature value was updated
+ *		earlier (in jiffies).
+ * @cpu_core_id: The CPU Core from which temperature values should be read
+ *		This value is passed as "id" field to rdmsr/wrmsr functions.
+ * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
+ *		from where the temperature values should be read.
+ * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
+ *		Otherwise, temp_data holds coretemp data.
+ * @valid: If this is 1, the current temperature is valid.
  */
-
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
-struct coretemp_data {
-	struct device *hwmon_dev;
-	struct mutex update_lock;
-	const char *name;
-	u32 id;
-	u16 core_id;
-	char valid;		/* zero until following fields are valid */
-	unsigned long last_updated;	/* in jiffies */
+struct temp_data {
 	int temp;
-	int tjmax;
 	int ttarget;
-	u8 alarm;
+	int tjmax;
+	unsigned long last_updated;
+	unsigned int cpu;
+	u32 cpu_core_id;
+	u32 status_reg;
+	bool is_pkg_data;
+	bool valid;
+	struct sensor_device_attribute sd_attrs[MAX_ATTRS];
+	char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH];
+	struct mutex update_lock;
 };
 
-/*
- * Sysfs stuff
- */
+/* Platform Data per Physical CPU */
+struct platform_data {
+	struct device *hwmon_dev;
+	u16 phys_proc_id;
+	struct temp_data *core_data[MAX_CORE_DATA];
+	struct device_attribute name_attr;
+};
 
-static ssize_t show_name(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
+struct pdev_entry {
+	struct list_head list;
+	struct platform_device *pdev;
+	unsigned int cpu;
+	u16 phys_proc_id;
+	u16 cpu_core_id;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static ssize_t show_name(struct device *dev,
+			struct device_attribute *devattr, char *buf)
 {
-	int ret;
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct coretemp_data *data = dev_get_drvdata(dev);
-
-	if (attr->index == SHOW_NAME)
-		ret = sprintf(buf, "%s\n", data->name);
-	else	/* show label */
-		ret = sprintf(buf, "Core %d\n", data->core_id);
-	return ret;
+	return sprintf(buf, "%s\n", DRVNAME);
 }
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
+static ssize_t show_label(struct device *dev,
+				struct device_attribute *devattr, char *buf)
 {
-	struct coretemp_data *data = coretemp_update_device(dev);
-	/* read the Out-of-spec log, never clear */
-	return sprintf(buf, "%d\n", data->alarm);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct platform_data *pdata = dev_get_drvdata(dev);
+	struct temp_data *tdata = pdata->core_data[attr->index];
+
+	if (tdata->is_pkg_data)
+		return sprintf(buf, "Physical id %u\n", pdata->phys_proc_id);
+
+	return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
+}
+
+static ssize_t show_crit_alarm(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	u32 eax, edx;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct platform_data *pdata = dev_get_drvdata(dev);
+	struct temp_data *tdata = pdata->core_data[attr->index];
+
+	rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+
+	return sprintf(buf, "%d\n", (eax >> 5) & 1);
+}
+
+static ssize_t show_tjmax(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct platform_data *pdata = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax);
+}
+
+static ssize_t show_ttarget(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct platform_data *pdata = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
 }
 
 static ssize_t show_temp(struct device *dev,
-			 struct device_attribute *devattr, char *buf)
+			struct device_attribute *devattr, char *buf)
 {
+	u32 eax, edx;
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct coretemp_data *data = coretemp_update_device(dev);
-	int err;
+	struct platform_data *pdata = dev_get_drvdata(dev);
+	struct temp_data *tdata = pdata->core_data[attr->index];
 
-	if (attr->index == SHOW_TEMP)
-		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
-	else if (attr->index == SHOW_TJMAX)
-		err = sprintf(buf, "%d\n", data->tjmax);
-	else
-		err = sprintf(buf, "%d\n", data->ttarget);
-	return err;
-}
+	mutex_lock(&tdata->update_lock);
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
-			  SHOW_TEMP);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
-			  SHOW_TJMAX);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
-			  SHOW_TTARGET);
-static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
-
-static struct attribute *coretemp_attributes[] = {
-	&sensor_dev_attr_name.dev_attr.attr,
-	&sensor_dev_attr_temp1_label.dev_attr.attr,
-	&dev_attr_temp1_crit_alarm.attr,
-	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit.dev_attr.attr,
-	NULL
-};
-
-static const struct attribute_group coretemp_group = {
-	.attrs = coretemp_attributes,
-};
-
-static struct coretemp_data *coretemp_update_device(struct device *dev)
-{
-	struct coretemp_data *data = dev_get_drvdata(dev);
-
-	mutex_lock(&data->update_lock);
-
-	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
-		u32 eax, edx;
-
-		data->valid = 0;
-		rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
-		data->alarm = (eax >> 5) & 1;
-		/* update only if data has been valid */
+	/* Check whether the time interval has elapsed */
+	if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) {
+		rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+		tdata->valid = 0;
+		/* Check whether the data is valid */
 		if (eax & 0x80000000) {
-			data->temp = data->tjmax - (((eax >> 16)
-							& 0x7f) * 1000);
-			data->valid = 1;
-		} else {
-			dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+			tdata->temp = tdata->tjmax -
+					((eax >> 16) & 0x7f) * 1000;
+			tdata->valid = 1;
 		}
-		data->last_updated = jiffies;
+		tdata->last_updated = jiffies;
 	}
 
-	mutex_unlock(&data->update_lock);
-	return data;
+	mutex_unlock(&tdata->update_lock);
+	return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
 }
 
-static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 {
 	/* The 100C is default for both mobile and non mobile CPUs */
 
@@ -169,9 +193,8 @@
 
 	/* Early chips have no MSR for TjMax */
 
-	if ((c->x86_model == 0xf) && (c->x86_mask < 4)) {
+	if (c->x86_model == 0xf && c->x86_mask < 4)
 		usemsr_ee = 0;
-	}
 
 	/* Atom CPUs */
 
@@ -190,14 +213,14 @@
 		pci_dev_put(host_bridge);
 	}
 
-	if ((c->x86_model > 0xe) && (usemsr_ee)) {
+	if (c->x86_model > 0xe && usemsr_ee) {
 		u8 platform_id;
 
-		/* Now we can detect the mobile CPU using Intel provided table
-		   http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
-		   For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
-		*/
-
+		/*
+		 * Now we can detect the mobile CPU using Intel provided table
+		 * http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
+		 * For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
+		 */
 		err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
 		if (err) {
 			dev_warn(dev,
@@ -205,20 +228,26 @@
 				 " CPU\n");
 			usemsr_ee = 0;
 		} else if (c->x86_model < 0x17 && !(eax & 0x10000000)) {
-			/* Trust bit 28 up to Penryn, I could not find any
-			   documentation on that; if you happen to know
-			   someone at Intel please ask */
+			/*
+			 * Trust bit 28 up to Penryn, I could not find any
+			 * documentation on that; if you happen to know
+			 * someone at Intel please ask
+			 */
 			usemsr_ee = 0;
 		} else {
 			/* Platform ID bits 52:50 (EDX starts at bit 32) */
 			platform_id = (edx >> 18) & 0x7;
 
-			/* Mobile Penryn CPU seems to be platform ID 7 or 5
-			  (guesswork) */
-			if ((c->x86_model == 0x17) &&
-			    ((platform_id == 5) || (platform_id == 7))) {
-				/* If MSR EE bit is set, set it to 90 degrees C,
-				   otherwise 105 degrees C */
+			/*
+			 * Mobile Penryn CPU seems to be platform ID 7 or 5
+			 * (guesswork)
+			 */
+			if (c->x86_model == 0x17 &&
+			    (platform_id == 5 || platform_id == 7)) {
+				/*
+				 * If MSR EE bit is set, set it to 90 degrees C,
+				 * otherwise 105 degrees C
+				 */
 				tjmax_ee = 90000;
 				tjmax = 105000;
 			}
@@ -226,7 +255,6 @@
 	}
 
 	if (usemsr_ee) {
-
 		err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
 		if (err) {
 			dev_warn(dev,
@@ -235,25 +263,28 @@
 		} else if (eax & 0x40000000) {
 			tjmax = tjmax_ee;
 		}
-	/* if we dont use msr EE it means we are desktop CPU (with exeception
-	   of Atom) */
 	} else if (tjmax == 100000) {
+		/*
+		 * If we don't use msr EE it means we are desktop CPU
+		 * (with exeception of Atom)
+		 */
 		dev_warn(dev, "Using relative temperature scale!\n");
 	}
 
 	return tjmax;
 }
 
-static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
-			       struct device *dev)
+static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 {
 	/* The 100C is default for both mobile and non mobile CPUs */
 	int err;
 	u32 eax, edx;
 	u32 val;
 
-	/* A new feature of current Intel(R) processors, the
-	   IA32_TEMPERATURE_TARGET contains the TjMax value */
+	/*
+	 * A new feature of current Intel(R) processors, the
+	 * IA32_TEMPERATURE_TARGET contains the TjMax value
+	 */
 	err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
 	if (err) {
 		dev_warn(dev, "Unable to read TjMax from CPU.\n");
@@ -263,7 +294,7 @@
 		 * If the TjMax is not plausible, an assumption
 		 * will be used
 		 */
-		if ((val > 80) && (val < 120)) {
+		if (val > 80 && val < 120) {
 			dev_info(dev, "TjMax is %d C.\n", val);
 			return val * 1000;
 		}
@@ -300,115 +331,293 @@
 	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
 }
 
-static int __devinit coretemp_probe(struct platform_device *pdev)
+static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
 {
-	struct coretemp_data *data;
-	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+	int err;
+	u32 eax, edx, val;
+
+	err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+	if (!err) {
+		val = (eax >> 16) & 0xff;
+		if (val > 80 && val < 120)
+			return val * 1000;
+	}
+	dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
+	return 100000; /* Default TjMax: 100 degree celsius */
+}
+
+static int create_name_attr(struct platform_data *pdata, struct device *dev)
+{
+	pdata->name_attr.attr.name = "name";
+	pdata->name_attr.attr.mode = S_IRUGO;
+	pdata->name_attr.show = show_name;
+	return device_create_file(dev, &pdata->name_attr);
+}
+
+static int create_core_attrs(struct temp_data *tdata, struct device *dev,
+				int attr_no)
+{
+	int err, i;
+	static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev,
+			struct device_attribute *devattr, char *buf) = {
+			show_label, show_crit_alarm, show_ttarget,
+			show_temp, show_tjmax };
+	static const char *names[MAX_ATTRS] = {
+					"temp%d_label", "temp%d_crit_alarm",
+					"temp%d_max", "temp%d_input",
+					"temp%d_crit" };
+
+	for (i = 0; i < MAX_ATTRS; i++) {
+		snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
+			attr_no);
+		tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
+		tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
+		tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
+		tdata->sd_attrs[i].dev_attr.store = NULL;
+		tdata->sd_attrs[i].index = attr_no;
+		err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
+		if (err)
+			goto exit_free;
+	}
+	return 0;
+
+exit_free:
+	while (--i >= 0)
+		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+	return err;
+}
+
+static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
+				struct device *dev)
+{
 	int err;
 	u32 eax, edx;
 
-	if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		dev_err(&pdev->dev, "Out of memory\n");
-		goto exit;
+	/*
+	 * Initialize ttarget value. Eventually this will be
+	 * initialized with the value from MSR_IA32_THERM_INTERRUPT
+	 * register. If IA32_TEMPERATURE_TARGET is supported, this
+	 * value will be over written below.
+	 * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT
+	 */
+	tdata->ttarget = tdata->tjmax - 20000;
+
+	/*
+	 * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
+	 * on older CPUs but not in this register,
+	 * Atoms don't have it either.
+	 */
+	if (cpu_model > 0xe && cpu_model != 0x1c) {
+		err = rdmsr_safe_on_cpu(tdata->cpu,
+				MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+			"Unable to read IA32_TEMPERATURE_TARGET MSR\n");
+		} else {
+			tdata->ttarget = tdata->tjmax -
+					((eax >> 8) & 0xff) * 1000;
+		}
 	}
+}
 
-	data->id = pdev->id;
-#ifdef CONFIG_SMP
-	data->core_id = c->cpu_core_id;
-#endif
-	data->name = "coretemp";
-	mutex_init(&data->update_lock);
+static int chk_ucode_version(struct platform_device *pdev)
+{
+	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+	int err;
+	u32 edx;
 
-	/* test if we can access the THERM_STATUS MSR */
-	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
-	if (err) {
-		dev_err(&pdev->dev,
-			"Unable to access THERM_STATUS MSR, giving up\n");
-		goto exit_free;
-	}
-
-	/* Check if we have problem with errata AE18 of Core processors:
-	   Readings might stop update when processor visited too deep sleep,
-	   fixed for stepping D0 (6EC).
-	*/
-
-	if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
+	/*
+	 * Check if we have problem with errata AE18 of Core processors:
+	 * Readings might stop update when processor visited too deep sleep,
+	 * fixed for stepping D0 (6EC).
+	 */
+	if (c->x86_model == 0xe && c->x86_mask < 0xc) {
 		/* check for microcode update */
-		err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
+		err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
 					       &edx, 1);
 		if (err) {
 			dev_err(&pdev->dev,
 				"Cannot determine microcode revision of "
-				"CPU#%u (%d)!\n", data->id, err);
-			err = -ENODEV;
-			goto exit_free;
+				"CPU#%u (%d)!\n", pdev->id, err);
+			return -ENODEV;
 		} else if (edx < 0x39) {
-			err = -ENODEV;
 			dev_err(&pdev->dev,
 				"Errata AE18 not fixed, update BIOS or "
 				"microcode of the CPU!\n");
-			goto exit_free;
+			return -ENODEV;
 		}
 	}
+	return 0;
+}
 
-	data->tjmax = get_tjmax(c, data->id, &pdev->dev);
-	platform_set_drvdata(pdev, data);
+static struct platform_device *coretemp_get_pdev(unsigned int cpu)
+{
+	u16 phys_proc_id = TO_PHYS_ID(cpu);
+	struct pdev_entry *p;
+
+	mutex_lock(&pdev_list_mutex);
+
+	list_for_each_entry(p, &pdev_list, list)
+		if (p->phys_proc_id == phys_proc_id) {
+			mutex_unlock(&pdev_list_mutex);
+			return p->pdev;
+		}
+
+	mutex_unlock(&pdev_list_mutex);
+	return NULL;
+}
+
+static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
+{
+	struct temp_data *tdata;
+
+	tdata = kzalloc(sizeof(struct temp_data), GFP_KERNEL);
+	if (!tdata)
+		return NULL;
+
+	tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
+							MSR_IA32_THERM_STATUS;
+	tdata->is_pkg_data = pkg_flag;
+	tdata->cpu = cpu;
+	tdata->cpu_core_id = TO_CORE_ID(cpu);
+	mutex_init(&tdata->update_lock);
+	return tdata;
+}
+
+static int create_core_data(struct platform_data *pdata,
+				struct platform_device *pdev,
+				unsigned int cpu, int pkg_flag)
+{
+	struct temp_data *tdata;
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	u32 eax, edx;
+	int err, attr_no;
 
 	/*
-	 * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
-	 * on older CPUs but not in this register,
-	 * Atoms don't have it either.
+	 * Find attr number for sysfs:
+	 * We map the attr number to core id of the CPU
+	 * The attr number is always core id + 2
+	 * The Pkgtemp will always show up as temp1_*, if available
 	 */
+	attr_no = pkg_flag ? 1 : TO_ATTR_NO(cpu);
 
-	if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
-		err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
-		    &eax, &edx);
-		if (err) {
-			dev_warn(&pdev->dev, "Unable to read"
-					" IA32_TEMPERATURE_TARGET MSR\n");
-		} else {
-			data->ttarget = data->tjmax -
-					(((eax >> 8) & 0xff) * 1000);
-			err = device_create_file(&pdev->dev,
-					&sensor_dev_attr_temp1_max.dev_attr);
-			if (err)
-				goto exit_free;
-		}
-	}
+	if (attr_no > MAX_CORE_DATA - 1)
+		return -ERANGE;
 
-	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
-		goto exit_dev;
+	/* Skip if it is a HT core, Not an error */
+	if (pdata->core_data[attr_no] != NULL)
+		return 0;
 
-	data->hwmon_dev = hwmon_device_register(&pdev->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		err = PTR_ERR(data->hwmon_dev);
-		dev_err(&pdev->dev, "Class registration failed (%d)\n",
-			err);
-		goto exit_class;
-	}
+	tdata = init_temp_data(cpu, pkg_flag);
+	if (!tdata)
+		return -ENOMEM;
+
+	/* Test if we can access the status register */
+	err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx);
+	if (err)
+		goto exit_free;
+
+	/* We can access status register. Get Critical Temperature */
+	if (pkg_flag)
+		tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
+	else
+		tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+
+	update_ttarget(c->x86_model, tdata, &pdev->dev);
+	pdata->core_data[attr_no] = tdata;
+
+	/* Create sysfs interfaces */
+	err = create_core_attrs(tdata, &pdev->dev, attr_no);
+	if (err)
+		goto exit_free;
 
 	return 0;
-
-exit_class:
-	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-exit_dev:
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
 exit_free:
-	kfree(data);
-exit:
+	kfree(tdata);
+	return err;
+}
+
+static void coretemp_add_core(unsigned int cpu, int pkg_flag)
+{
+	struct platform_data *pdata;
+	struct platform_device *pdev = coretemp_get_pdev(cpu);
+	int err;
+
+	if (!pdev)
+		return;
+
+	pdata = platform_get_drvdata(pdev);
+
+	err = create_core_data(pdata, pdev, cpu, pkg_flag);
+	if (err)
+		dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
+}
+
+static void coretemp_remove_core(struct platform_data *pdata,
+				struct device *dev, int indx)
+{
+	int i;
+	struct temp_data *tdata = pdata->core_data[indx];
+
+	/* Remove the sysfs attributes */
+	for (i = 0; i < MAX_ATTRS; i++)
+		device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+
+	kfree(pdata->core_data[indx]);
+	pdata->core_data[indx] = NULL;
+}
+
+static int __devinit coretemp_probe(struct platform_device *pdev)
+{
+	struct platform_data *pdata;
+	int err;
+
+	/* Check the microcode version of the CPU */
+	err = chk_ucode_version(pdev);
+	if (err)
+		return err;
+
+	/* Initialize the per-package data structures */
+	pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	err = create_name_attr(pdata, &pdev->dev);
+	if (err)
+		goto exit_free;
+
+	pdata->phys_proc_id = TO_PHYS_ID(pdev->id);
+	platform_set_drvdata(pdev, pdata);
+
+	pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(pdata->hwmon_dev)) {
+		err = PTR_ERR(pdata->hwmon_dev);
+		dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+		goto exit_name;
+	}
+	return 0;
+
+exit_name:
+	device_remove_file(&pdev->dev, &pdata->name_attr);
+	platform_set_drvdata(pdev, NULL);
+exit_free:
+	kfree(pdata);
 	return err;
 }
 
 static int __devexit coretemp_remove(struct platform_device *pdev)
 {
-	struct coretemp_data *data = platform_get_drvdata(pdev);
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	int i;
 
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
+	for (i = MAX_CORE_DATA - 1; i >= 0; --i)
+		if (pdata->core_data[i])
+			coretemp_remove_core(pdata, &pdev->dev, i);
+
+	device_remove_file(&pdev->dev, &pdata->name_attr);
+	hwmon_device_unregister(pdata->hwmon_dev);
 	platform_set_drvdata(pdev, NULL);
-	kfree(data);
+	kfree(pdata);
 	return 0;
 }
 
@@ -421,50 +630,14 @@
 	.remove = __devexit_p(coretemp_remove),
 };
 
-struct pdev_entry {
-	struct list_head list;
-	struct platform_device *pdev;
-	unsigned int cpu;
-#ifdef CONFIG_SMP
-	u16 phys_proc_id;
-	u16 cpu_core_id;
-#endif
-};
-
-static LIST_HEAD(pdev_list);
-static DEFINE_MUTEX(pdev_list_mutex);
-
 static int __cpuinit coretemp_device_add(unsigned int cpu)
 {
 	int err;
 	struct platform_device *pdev;
 	struct pdev_entry *pdev_entry;
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
-
-	/*
-	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
-	 * sensors. We check this bit only, all the early CPUs
-	 * without thermal sensors will be filtered out.
-	 */
-	if (!cpu_has(c, X86_FEATURE_DTS)) {
-		pr_info("CPU (model=0x%x) has no thermal sensor\n",
-			c->x86_model);
-		return 0;
-	}
 
 	mutex_lock(&pdev_list_mutex);
 
-#ifdef CONFIG_SMP
-	/* Skip second HT entry of each core */
-	list_for_each_entry(pdev_entry, &pdev_list, list) {
-		if (c->phys_proc_id == pdev_entry->phys_proc_id &&
-		    c->cpu_core_id == pdev_entry->cpu_core_id) {
-			err = 0;	/* Not an error */
-			goto exit;
-		}
-	}
-#endif
-
 	pdev = platform_device_alloc(DRVNAME, cpu);
 	if (!pdev) {
 		err = -ENOMEM;
@@ -486,10 +659,9 @@
 
 	pdev_entry->pdev = pdev;
 	pdev_entry->cpu = cpu;
-#ifdef CONFIG_SMP
-	pdev_entry->phys_proc_id = c->phys_proc_id;
-	pdev_entry->cpu_core_id = c->cpu_core_id;
-#endif
+	pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
+	pdev_entry->cpu_core_id = TO_CORE_ID(cpu);
+
 	list_add_tail(&pdev_entry->list, &pdev_list);
 	mutex_unlock(&pdev_list_mutex);
 
@@ -504,28 +676,108 @@
 	return err;
 }
 
-static void __cpuinit coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
 {
-	struct pdev_entry *p;
-	unsigned int i;
+	struct pdev_entry *p, *n;
+	u16 phys_proc_id = TO_PHYS_ID(cpu);
 
 	mutex_lock(&pdev_list_mutex);
-	list_for_each_entry(p, &pdev_list, list) {
-		if (p->cpu != cpu)
+	list_for_each_entry_safe(p, n, &pdev_list, list) {
+		if (p->phys_proc_id != phys_proc_id)
 			continue;
-
 		platform_device_unregister(p->pdev);
 		list_del(&p->list);
-		mutex_unlock(&pdev_list_mutex);
 		kfree(p);
-		for_each_cpu(i, cpu_sibling_mask(cpu))
-			if (i != cpu && !coretemp_device_add(i))
-				break;
-		return;
 	}
 	mutex_unlock(&pdev_list_mutex);
 }
 
+static bool is_any_core_online(struct platform_data *pdata)
+{
+	int i;
+
+	/* Find online cores, except pkgtemp data */
+	for (i = MAX_CORE_DATA - 1; i >= 0; --i) {
+		if (pdata->core_data[i] &&
+			!pdata->core_data[i]->is_pkg_data) {
+			return true;
+		}
+	}
+	return false;
+}
+
+static void __cpuinit get_core_online(unsigned int cpu)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct platform_device *pdev = coretemp_get_pdev(cpu);
+	int err;
+
+	/*
+	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+	 * sensors. We check this bit only, all the early CPUs
+	 * without thermal sensors will be filtered out.
+	 */
+	if (!cpu_has(c, X86_FEATURE_DTS))
+		return;
+
+	if (!pdev) {
+		/*
+		 * Alright, we have DTS support.
+		 * We are bringing the _first_ core in this pkg
+		 * online. So, initialize per-pkg data structures and
+		 * then bring this core online.
+		 */
+		err = coretemp_device_add(cpu);
+		if (err)
+			return;
+		/*
+		 * Check whether pkgtemp support is available.
+		 * If so, add interfaces for pkgtemp.
+		 */
+		if (cpu_has(c, X86_FEATURE_PTS))
+			coretemp_add_core(cpu, 1);
+	}
+	/*
+	 * Physical CPU device already exists.
+	 * So, just add interfaces for this core.
+	 */
+	coretemp_add_core(cpu, 0);
+}
+
+static void __cpuinit put_core_offline(unsigned int cpu)
+{
+	int i, indx;
+	struct platform_data *pdata;
+	struct platform_device *pdev = coretemp_get_pdev(cpu);
+
+	/* If the physical CPU device does not exist, just return */
+	if (!pdev)
+		return;
+
+	pdata = platform_get_drvdata(pdev);
+
+	indx = TO_ATTR_NO(cpu);
+
+	if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
+		coretemp_remove_core(pdata, &pdev->dev, indx);
+
+	/* Online the HT version of this core, if any */
+	for_each_cpu(i, cpu_sibling_mask(cpu)) {
+		if (i != cpu) {
+			get_core_online(i);
+			break;
+		}
+	}
+	/*
+	 * If all cores in this pkg are offline, remove the device.
+	 * coretemp_device_remove calls unregister_platform_device,
+	 * which in turn calls coretemp_remove. This removes the
+	 * pkgtemp entry and does other clean ups.
+	 */
+	if (!is_any_core_online(pdata))
+		coretemp_device_remove(cpu);
+}
+
 static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
 				 unsigned long action, void *hcpu)
 {
@@ -534,10 +786,10 @@
 	switch (action) {
 	case CPU_ONLINE:
 	case CPU_DOWN_FAILED:
-		coretemp_device_add(cpu);
+		get_core_online(cpu);
 		break;
 	case CPU_DOWN_PREPARE:
-		coretemp_device_remove(cpu);
+		put_core_offline(cpu);
 		break;
 	}
 	return NOTIFY_OK;
@@ -560,7 +812,7 @@
 		goto exit;
 
 	for_each_online_cpu(i)
-		coretemp_device_add(i);
+		get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
new file mode 100644
index 0000000..d94a24f
--- /dev/null
+++ b/drivers/hwmon/max16065.c
@@ -0,0 +1,717 @@
+/*
+ * Driver for
+ *  Maxim MAX16065/MAX16066 12-Channel/8-Channel, Flash-Configurable
+ *  System Managers with Nonvolatile Fault Registers
+ *  Maxim MAX16067/MAX16068 6-Channel, Flash-Configurable System Managers
+ *  with Nonvolatile Fault Registers
+ *  Maxim MAX16070/MAX16071 12-Channel/8-Channel, Flash-Configurable System
+ *  Monitors with Nonvolatile Fault Registers
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+enum chips { max16065, max16066, max16067, max16068, max16070, max16071 };
+
+/*
+ * Registers
+ */
+#define MAX16065_ADC(x)		((x) * 2)
+
+#define MAX16065_CURR_SENSE	0x18
+#define MAX16065_CSP_ADC	0x19
+#define MAX16065_FAULT(x)	(0x1b + (x))
+#define MAX16065_SCALE(x)	(0x43 + (x))
+#define MAX16065_CURR_CONTROL	0x47
+#define MAX16065_LIMIT(l, x)	(0x48 + (l) + (x) * 3)	/*
+							 * l: limit
+							 *  0: min/max
+							 *  1: crit
+							 *  2: lcrit
+							 * x: ADC index
+							 */
+
+#define MAX16065_SW_ENABLE	0x73
+
+#define MAX16065_WARNING_OV	(1 << 3) /* Set if secondary threshold is OV
+					    warning */
+
+#define MAX16065_CURR_ENABLE	(1 << 0)
+
+#define MAX16065_NUM_LIMIT	3
+#define MAX16065_NUM_ADC	12	/* maximum number of ADC channels */
+
+static const int max16065_num_adc[] = {
+	[max16065] = 12,
+	[max16066] = 8,
+	[max16067] = 6,
+	[max16068] = 6,
+	[max16070] = 12,
+	[max16071] = 8,
+};
+
+static const bool max16065_have_secondary[] = {
+	[max16065] = true,
+	[max16066] = true,
+	[max16067] = false,
+	[max16068] = false,
+	[max16070] = true,
+	[max16071] = true,
+};
+
+static const bool max16065_have_current[] = {
+	[max16065] = true,
+	[max16066] = true,
+	[max16067] = false,
+	[max16068] = false,
+	[max16070] = true,
+	[max16071] = true,
+};
+
+struct max16065_data {
+	enum chips type;
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+	int num_adc;
+	bool have_current;
+	int curr_gain;
+	/* limits are in mV */
+	int limit[MAX16065_NUM_LIMIT][MAX16065_NUM_ADC];
+	int range[MAX16065_NUM_ADC + 1];/* voltage range */
+	int adc[MAX16065_NUM_ADC + 1];	/* adc values (raw) including csp_adc */
+	int curr_sense;
+	int fault[2];
+};
+
+static const int max16065_adc_range[] = { 5560, 2780, 1390, 0 };
+static const int max16065_csp_adc_range[] = { 7000, 14000 };
+
+/* ADC registers have 10 bit resolution. */
+static inline int ADC_TO_MV(int adc, int range)
+{
+	return (adc * range) / 1024;
+}
+
+/*
+ * Limit registers have 8 bit resolution and match upper 8 bits of ADC
+ * registers.
+ */
+static inline int LIMIT_TO_MV(int limit, int range)
+{
+	return limit * range / 256;
+}
+
+static inline int MV_TO_LIMIT(int mv, int range)
+{
+	return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
+}
+
+static inline int ADC_TO_CURR(int adc, int gain)
+{
+	return adc * 1400000 / gain * 255;
+}
+
+/*
+ * max16065_read_adc()
+ *
+ * Read 16 bit value from <reg>, <reg+1>.
+ * Upper 8 bits are in <reg>, lower 2 bits are in bits 7:6 of <reg+1>.
+ */
+static int max16065_read_adc(struct i2c_client *client, int reg)
+{
+	int rv;
+
+	rv = i2c_smbus_read_word_data(client, reg);
+	if (unlikely(rv < 0))
+		return rv;
+	return ((rv & 0xff) << 2) | ((rv >> 14) & 0x03);
+}
+
+static struct max16065_data *max16065_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max16065_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->update_lock);
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		int i;
+
+		for (i = 0; i < data->num_adc; i++)
+			data->adc[i]
+			  = max16065_read_adc(client, MAX16065_ADC(i));
+
+		if (data->have_current) {
+			data->adc[MAX16065_NUM_ADC]
+			  = max16065_read_adc(client, MAX16065_CSP_ADC);
+			data->curr_sense
+			  = i2c_smbus_read_byte_data(client,
+						     MAX16065_CURR_SENSE);
+		}
+
+		for (i = 0; i < DIV_ROUND_UP(data->num_adc, 8); i++)
+			data->fault[i]
+			  = i2c_smbus_read_byte_data(client, MAX16065_FAULT(i));
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static ssize_t max16065_show_alarm(struct device *dev,
+				   struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+	struct max16065_data *data = max16065_update_device(dev);
+	int val = data->fault[attr2->nr];
+
+	if (val < 0)
+		return val;
+
+	val &= (1 << attr2->index);
+	if (val)
+		i2c_smbus_write_byte_data(to_i2c_client(dev),
+					  MAX16065_FAULT(attr2->nr), val);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!val);
+}
+
+static ssize_t max16065_show_input(struct device *dev,
+				   struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct max16065_data *data = max16065_update_device(dev);
+	int adc = data->adc[attr->index];
+
+	if (unlikely(adc < 0))
+		return adc;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			ADC_TO_MV(adc, data->range[attr->index]));
+}
+
+static ssize_t max16065_show_current(struct device *dev,
+				     struct device_attribute *da, char *buf)
+{
+	struct max16065_data *data = max16065_update_device(dev);
+
+	if (unlikely(data->curr_sense < 0))
+		return data->curr_sense;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			ADC_TO_CURR(data->curr_sense, data->curr_gain));
+}
+
+static ssize_t max16065_set_limit(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max16065_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+	int limit;
+
+	err = strict_strtoul(buf, 10, &val);
+	if (unlikely(err < 0))
+		return err;
+
+	limit = MV_TO_LIMIT(val, data->range[attr2->index]);
+
+	mutex_lock(&data->update_lock);
+	data->limit[attr2->nr][attr2->index]
+	  = LIMIT_TO_MV(limit, data->range[attr2->index]);
+	i2c_smbus_write_byte_data(client,
+				  MAX16065_LIMIT(attr2->nr, attr2->index),
+				  limit);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t max16065_show_limit(struct device *dev,
+				   struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max16065_data *data = i2c_get_clientdata(client);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			data->limit[attr2->nr][attr2->index]);
+}
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Input voltages */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, max16065_show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, max16065_show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, max16065_show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, max16065_show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, max16065_show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, max16065_show_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, max16065_show_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, max16065_show_input, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, max16065_show_input, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, max16065_show_input, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, max16065_show_input, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, max16065_show_input, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, max16065_show_input, NULL, 12);
+
+/* Input voltages lcrit */
+static SENSOR_DEVICE_ATTR_2(in0_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in1_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 2);
+static SENSOR_DEVICE_ATTR_2(in3_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 3);
+static SENSOR_DEVICE_ATTR_2(in4_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 4);
+static SENSOR_DEVICE_ATTR_2(in5_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 5);
+static SENSOR_DEVICE_ATTR_2(in6_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 6);
+static SENSOR_DEVICE_ATTR_2(in7_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 7);
+static SENSOR_DEVICE_ATTR_2(in8_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 8);
+static SENSOR_DEVICE_ATTR_2(in9_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 9);
+static SENSOR_DEVICE_ATTR_2(in10_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 10);
+static SENSOR_DEVICE_ATTR_2(in11_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 2, 11);
+
+/* Input voltages crit */
+static SENSOR_DEVICE_ATTR_2(in0_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in2_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 2);
+static SENSOR_DEVICE_ATTR_2(in3_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 3);
+static SENSOR_DEVICE_ATTR_2(in4_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 4);
+static SENSOR_DEVICE_ATTR_2(in5_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 5);
+static SENSOR_DEVICE_ATTR_2(in6_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 6);
+static SENSOR_DEVICE_ATTR_2(in7_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 7);
+static SENSOR_DEVICE_ATTR_2(in8_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 8);
+static SENSOR_DEVICE_ATTR_2(in9_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 9);
+static SENSOR_DEVICE_ATTR_2(in10_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 10);
+static SENSOR_DEVICE_ATTR_2(in11_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 1, 11);
+
+/* Input voltages min */
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 8);
+static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 9);
+static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 10);
+static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 11);
+
+/* Input voltages max */
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 8);
+static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 9);
+static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 10);
+static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+			    max16065_set_limit, 0, 11);
+
+/* alarms */
+static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    1, 0);
+static SENSOR_DEVICE_ATTR_2(in9_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(in10_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    1, 2);
+static SENSOR_DEVICE_ATTR_2(in11_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    1, 3);
+
+/* Current and alarm */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, max16065_show_current, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(curr1_alarm, S_IRUGO, max16065_show_alarm, NULL,
+			    1, 4);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *max16065_basic_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in0_crit.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in1_crit.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in2_crit.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in3_crit.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in4_crit.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in5_crit.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in6_crit.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in7_crit.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in8_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in8_crit.dev_attr.attr,
+	&sensor_dev_attr_in8_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in9_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in9_crit.dev_attr.attr,
+	&sensor_dev_attr_in9_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in10_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in10_crit.dev_attr.attr,
+	&sensor_dev_attr_in10_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in11_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in11_crit.dev_attr.attr,
+	&sensor_dev_attr_in11_alarm.dev_attr.attr,
+
+	NULL
+};
+
+static struct attribute *max16065_current_attributes[] = {
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *max16065_min_attributes[] = {
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in8_min.dev_attr.attr,
+	&sensor_dev_attr_in9_min.dev_attr.attr,
+	&sensor_dev_attr_in10_min.dev_attr.attr,
+	&sensor_dev_attr_in11_min.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *max16065_max_attributes[] = {
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in8_max.dev_attr.attr,
+	&sensor_dev_attr_in9_max.dev_attr.attr,
+	&sensor_dev_attr_in10_max.dev_attr.attr,
+	&sensor_dev_attr_in11_max.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max16065_basic_group = {
+	.attrs = max16065_basic_attributes,
+};
+
+static const struct attribute_group max16065_current_group = {
+	.attrs = max16065_current_attributes,
+};
+
+static const struct attribute_group max16065_min_group = {
+	.attrs = max16065_min_attributes,
+};
+
+static const struct attribute_group max16065_max_group = {
+	.attrs = max16065_max_attributes,
+};
+
+static void max16065_cleanup(struct i2c_client *client)
+{
+	sysfs_remove_group(&client->dev.kobj, &max16065_max_group);
+	sysfs_remove_group(&client->dev.kobj, &max16065_min_group);
+	sysfs_remove_group(&client->dev.kobj, &max16065_current_group);
+	sysfs_remove_group(&client->dev.kobj, &max16065_basic_group);
+}
+
+static int max16065_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct max16065_data *data;
+	int i, j, val, ret;
+	bool have_secondary;		/* true if chip has secondary limits */
+	bool secondary_is_max = false;	/* secondary limits reflect max */
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+				     | I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -ENODEV;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (unlikely(!data))
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	data->num_adc = max16065_num_adc[id->driver_data];
+	data->have_current = max16065_have_current[id->driver_data];
+	have_secondary = max16065_have_secondary[id->driver_data];
+
+	if (have_secondary) {
+		val = i2c_smbus_read_byte_data(client, MAX16065_SW_ENABLE);
+		if (unlikely(val < 0)) {
+			ret = val;
+			goto out_free;
+		}
+		secondary_is_max = val & MAX16065_WARNING_OV;
+	}
+
+	/* Read scale registers, convert to range */
+	for (i = 0; i < DIV_ROUND_UP(data->num_adc, 4); i++) {
+		val = i2c_smbus_read_byte_data(client, MAX16065_SCALE(i));
+		if (unlikely(val < 0)) {
+			ret = val;
+			goto out_free;
+		}
+		for (j = 0; j < 4 && i * 4 + j < data->num_adc; j++) {
+			data->range[i * 4 + j] =
+			  max16065_adc_range[(val >> (j * 2)) & 0x3];
+		}
+	}
+
+	/* Read limits */
+	for (i = 0; i < MAX16065_NUM_LIMIT; i++) {
+		if (i == 0 && !have_secondary)
+			continue;
+
+		for (j = 0; j < data->num_adc; j++) {
+			val = i2c_smbus_read_byte_data(client,
+						       MAX16065_LIMIT(i, j));
+			if (unlikely(val < 0)) {
+				ret = val;
+				goto out_free;
+			}
+			data->limit[i][j] = LIMIT_TO_MV(val, data->range[j]);
+		}
+	}
+
+	/* Register sysfs hooks */
+	for (i = 0; i < data->num_adc * 4; i++) {
+		/* Do not create sysfs entry if channel is disabled */
+		if (!data->range[i / 4])
+			continue;
+
+		ret = sysfs_create_file(&client->dev.kobj,
+					max16065_basic_attributes[i]);
+		if (unlikely(ret))
+			goto out;
+	}
+
+	if (have_secondary) {
+		struct attribute **attr = secondary_is_max ?
+		  max16065_max_attributes : max16065_min_attributes;
+
+		for (i = 0; i < data->num_adc; i++) {
+			if (!data->range[i])
+				continue;
+
+			ret = sysfs_create_file(&client->dev.kobj, attr[i]);
+			if (unlikely(ret))
+				goto out;
+		}
+	}
+
+	if (data->have_current) {
+		val = i2c_smbus_read_byte_data(client, MAX16065_CURR_CONTROL);
+		if (unlikely(val < 0)) {
+			ret = val;
+			goto out;
+		}
+		if (val & MAX16065_CURR_ENABLE) {
+			/*
+			 * Current gain is 6, 12, 24, 48 based on values in
+			 * bit 2,3.
+			 */
+			data->curr_gain = 6 << ((val >> 2) & 0x03);
+			data->range[MAX16065_NUM_ADC]
+			  = max16065_csp_adc_range[(val >> 1) & 0x01];
+			ret = sysfs_create_group(&client->dev.kobj,
+						 &max16065_current_group);
+			if (unlikely(ret))
+				goto out;
+		} else {
+			data->have_current = false;
+		}
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (unlikely(IS_ERR(data->hwmon_dev))) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto out;
+	}
+	return 0;
+
+out:
+	max16065_cleanup(client);
+out_free:
+	kfree(data);
+	return ret;
+}
+
+static int max16065_remove(struct i2c_client *client)
+{
+	struct max16065_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	max16065_cleanup(client);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id max16065_id[] = {
+	{ "max16065", max16065 },
+	{ "max16066", max16066 },
+	{ "max16067", max16067 },
+	{ "max16068", max16068 },
+	{ "max16070", max16070 },
+	{ "max16071", max16071 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, max16065_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max16065_driver = {
+	.driver = {
+		.name = "max16065",
+	},
+	.probe = max16065_probe,
+	.remove = max16065_remove,
+	.id_table = max16065_id,
+};
+
+static int __init max16065_init(void)
+{
+	return i2c_add_driver(&max16065_driver);
+}
+
+static void __exit max16065_exit(void)
+{
+	i2c_del_driver(&max16065_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("MAX16065 driver");
+MODULE_LICENSE("GPL");
+
+module_init(max16065_init);
+module_exit(max16065_exit);
diff --git a/drivers/hwmon/max34440.c b/drivers/hwmon/max34440.c
index 992b701..db11e1a 100644
--- a/drivers/hwmon/max34440.c
+++ b/drivers/hwmon/max34440.c
@@ -32,7 +32,7 @@
 #define MAX34440_STATUS_OT_FAULT	(1 << 5)
 #define MAX34440_STATUS_OT_WARN		(1 << 6)
 
-static int max34440_get_status(struct i2c_client *client, int page, int reg)
+static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
 {
 	int ret;
 	int mfg_status;
@@ -108,7 +108,7 @@
 		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-		.get_status = max34440_get_status,
+		.read_byte_data = max34440_read_byte_data,
 	},
 	[max34441] = {
 		.pages = 12,
@@ -149,7 +149,7 @@
 		.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-		.get_status = max34440_get_status,
+		.read_byte_data = max34440_read_byte_data,
 	},
 };
 
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
new file mode 100644
index 0000000..0f9fc40
--- /dev/null
+++ b/drivers/hwmon/max6642.c
@@ -0,0 +1,356 @@
+/*
+ * Driver for +/-1 degree C, SMBus-Compatible Remote/Local Temperature Sensor
+ * with Overtemperature Alarm
+ *
+ * Copyright (C) 2011 AppearTV AS
+ *
+ * Derived from:
+ *
+ *  Based on the max1619 driver.
+ *  Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ *                          Jean Delvare <khali@linux-fr.org>
+ *
+ * The MAX6642 is a sensor chip made by Maxim.
+ * It reports up to two temperatures (its own plus up to
+ * one external one). Complete datasheet can be
+ * obtained from Maxim's website at:
+ *   http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#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/sysfs.h>
+
+static const unsigned short normal_i2c[] = {
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+
+/*
+ * The MAX6642 registers
+ */
+
+#define MAX6642_REG_R_MAN_ID		0xFE
+#define MAX6642_REG_R_CONFIG		0x03
+#define MAX6642_REG_W_CONFIG		0x09
+#define MAX6642_REG_R_STATUS		0x02
+#define MAX6642_REG_R_LOCAL_TEMP	0x00
+#define MAX6642_REG_R_LOCAL_TEMPL	0x11
+#define MAX6642_REG_R_LOCAL_HIGH	0x05
+#define MAX6642_REG_W_LOCAL_HIGH	0x0B
+#define MAX6642_REG_R_REMOTE_TEMP	0x01
+#define MAX6642_REG_R_REMOTE_TEMPL	0x10
+#define MAX6642_REG_R_REMOTE_HIGH	0x07
+#define MAX6642_REG_W_REMOTE_HIGH	0x0D
+
+/*
+ * Conversions
+ */
+
+static int temp_from_reg10(int val)
+{
+	return val * 250;
+}
+
+static int temp_from_reg(int val)
+{
+	return val * 1000;
+}
+
+static int temp_to_reg(int val)
+{
+	return val / 1000;
+}
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max6642_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	bool valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	u16 temp_input[2]; /* local/remote */
+	u16 temp_high[2]; /* local/remote */
+	u8 alarms;
+};
+
+/*
+ * Real code
+ */
+
+static void max6642_init_client(struct i2c_client *client)
+{
+	u8 config;
+	struct max6642_data *data = i2c_get_clientdata(client);
+
+	/*
+	 * Start the conversions.
+	 */
+	config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
+	if (config & 0x40)
+		i2c_smbus_write_byte_data(client, MAX6642_REG_W_CONFIG,
+					  config & 0xBF); /* run */
+
+	data->temp_high[0] = i2c_smbus_read_byte_data(client,
+				MAX6642_REG_R_LOCAL_HIGH);
+	data->temp_high[1] = i2c_smbus_read_byte_data(client,
+				MAX6642_REG_R_REMOTE_HIGH);
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6642_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u8 reg_config, reg_status, man_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* identification */
+	man_id = i2c_smbus_read_byte_data(client, MAX6642_REG_R_MAN_ID);
+	if (man_id != 0x4D)
+		return -ENODEV;
+
+	/*
+	 * We read the config and status register, the 4 lower bits in the
+	 * config register should be zero and bit 5, 3, 1 and 0 should be
+	 * zero in the status register.
+	 */
+	reg_config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
+	reg_status = i2c_smbus_read_byte_data(client, MAX6642_REG_R_STATUS);
+	if (((reg_config & 0x0f) != 0x00) ||
+	    ((reg_status & 0x2b) != 0x00))
+		return -ENODEV;
+
+	strlcpy(info->type, "max6642", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static struct max6642_data *max6642_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6642_data *data = i2c_get_clientdata(client);
+	u16 val, tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		dev_dbg(&client->dev, "Updating max6642 data.\n");
+		val = i2c_smbus_read_byte_data(client,
+					MAX6642_REG_R_LOCAL_TEMPL);
+		tmp = (val >> 6) & 3;
+		val = i2c_smbus_read_byte_data(client,
+					MAX6642_REG_R_LOCAL_TEMP);
+		val = (val << 2) | tmp;
+		data->temp_input[0] = val;
+		val = i2c_smbus_read_byte_data(client,
+					MAX6642_REG_R_REMOTE_TEMPL);
+		tmp = (val >> 6) & 3;
+		val = i2c_smbus_read_byte_data(client,
+					MAX6642_REG_R_REMOTE_TEMP);
+		val = (val << 2) | tmp;
+		data->temp_input[1] = val;
+		data->alarms = i2c_smbus_read_byte_data(client,
+					MAX6642_REG_R_STATUS);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_temp_max10(struct device *dev,
+			       struct device_attribute *dev_attr, char *buf)
+{
+	struct max6642_data *data = max6642_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	return sprintf(buf, "%d\n",
+		       temp_from_reg10(data->temp_input[attr->index]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct max6642_data *data = max6642_update_device(dev);
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n", temp_from_reg(data->temp_high[attr2->nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long val;
+	int err;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6642_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
+	i2c_smbus_write_byte_data(client, attr2->index,
+				  data->temp_high[attr2->nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct max6642_data *data = max6642_update_device(dev);
+	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_max10, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_max10, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+			    set_temp_max, 0, MAX6642_REG_W_LOCAL_HIGH);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+			    set_temp_max, 1, MAX6642_REG_W_REMOTE_HIGH);
+static SENSOR_DEVICE_ATTR(temp_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+static struct attribute *max6642_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+
+	&sensor_dev_attr_temp_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max6642_group = {
+	.attrs = max6642_attributes,
+};
+
+static int max6642_probe(struct i2c_client *new_client,
+			 const struct i2c_device_id *id)
+{
+	struct max6642_data *data;
+	int err;
+
+	data = kzalloc(sizeof(struct max6642_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(new_client, data);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the MAX6642 chip */
+	max6642_init_client(new_client);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&new_client->dev.kobj, &max6642_group);
+	if (err)
+		goto exit_free;
+
+	data->hwmon_dev = hwmon_device_register(&new_client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+
+	return 0;
+
+exit_remove_files:
+	sysfs_remove_group(&new_client->dev.kobj, &max6642_group);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int max6642_remove(struct i2c_client *client)
+{
+	struct max6642_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &max6642_group);
+
+	kfree(data);
+	return 0;
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id max6642_id[] = {
+	{ "max6642", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max6642_id);
+
+static struct i2c_driver max6642_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "max6642",
+	},
+	.probe		= max6642_probe,
+	.remove		= max6642_remove,
+	.id_table	= max6642_id,
+	.detect		= max6642_detect,
+	.address_list	= normal_i2c,
+};
+
+static int __init max6642_init(void)
+{
+	return i2c_add_driver(&max6642_driver);
+}
+
+static void __exit max6642_exit(void)
+{
+	i2c_del_driver(&max6642_driver);
+}
+
+MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
+MODULE_DESCRIPTION("MAX6642 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(max6642_init);
+module_exit(max6642_exit);
diff --git a/drivers/hwmon/max8688.c b/drivers/hwmon/max8688.c
index 8ebfef2..7fb93f4 100644
--- a/drivers/hwmon/max8688.c
+++ b/drivers/hwmon/max8688.c
@@ -37,7 +37,7 @@
 #define MAX8688_STATUS_OT_FAULT		(1 << 13)
 #define MAX8688_STATUS_OT_WARNING	(1 << 14)
 
-static int max8688_get_status(struct i2c_client *client, int page, int reg)
+static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
 {
 	int ret = 0;
 	int mfg_status;
@@ -110,7 +110,7 @@
 	.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
 		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
 		| PMBUS_HAVE_STATUS_TEMP,
-	.get_status = max8688_get_status,
+	.read_byte_data = max8688_read_byte_data,
 };
 
 static int max8688_probe(struct i2c_client *client,
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
deleted file mode 100644
index 21c817d..0000000
--- a/drivers/hwmon/pkgtemp.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * pkgtemp.c - Linux kernel module for processor package hardware monitoring
- *
- * Copyright (C) 2010 Fenghua Yu <fenghua.yu@intel.com>
- *
- * Inspired from many hwmon drivers especially coretemp.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/hwmon.h>
-#include <linux/sysfs.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/cpu.h>
-#include <asm/msr.h>
-#include <asm/processor.h>
-#include <asm/smp.h>
-
-#define DRVNAME	"pkgtemp"
-
-enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, SHOW_NAME };
-
-/*
- * Functions declaration
- */
-
-static struct pkgtemp_data *pkgtemp_update_device(struct device *dev);
-
-struct pkgtemp_data {
-	struct device *hwmon_dev;
-	struct mutex update_lock;
-	const char *name;
-	u32 id;
-	u16 phys_proc_id;
-	char valid;		/* zero until following fields are valid */
-	unsigned long last_updated;	/* in jiffies */
-	int temp;
-	int tjmax;
-	int ttarget;
-	u8 alarm;
-};
-
-/*
- * Sysfs stuff
- */
-
-static ssize_t show_name(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
-{
-	int ret;
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct pkgtemp_data *data = dev_get_drvdata(dev);
-
-	if (attr->index == SHOW_NAME)
-		ret = sprintf(buf, "%s\n", data->name);
-	else	/* show label */
-		ret = sprintf(buf, "physical id %d\n",
-			      data->phys_proc_id);
-	return ret;
-}
-
-static ssize_t show_alarm(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
-{
-	struct pkgtemp_data *data = pkgtemp_update_device(dev);
-	/* read the Out-of-spec log, never clear */
-	return sprintf(buf, "%d\n", data->alarm);
-}
-
-static ssize_t show_temp(struct device *dev,
-			 struct device_attribute *devattr, char *buf)
-{
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct pkgtemp_data *data = pkgtemp_update_device(dev);
-	int err = 0;
-
-	if (attr->index == SHOW_TEMP)
-		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
-	else if (attr->index == SHOW_TJMAX)
-		err = sprintf(buf, "%d\n", data->tjmax);
-	else
-		err = sprintf(buf, "%d\n", data->ttarget);
-	return err;
-}
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, SHOW_TEMP);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, SHOW_TJMAX);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, SHOW_TTARGET);
-static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
-
-static struct attribute *pkgtemp_attributes[] = {
-	&sensor_dev_attr_name.dev_attr.attr,
-	&sensor_dev_attr_temp1_label.dev_attr.attr,
-	&dev_attr_temp1_crit_alarm.attr,
-	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit.dev_attr.attr,
-	NULL
-};
-
-static const struct attribute_group pkgtemp_group = {
-	.attrs = pkgtemp_attributes,
-};
-
-static struct pkgtemp_data *pkgtemp_update_device(struct device *dev)
-{
-	struct pkgtemp_data *data = dev_get_drvdata(dev);
-	unsigned int cpu;
-	int err;
-
-	mutex_lock(&data->update_lock);
-
-	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
-		u32 eax, edx;
-
-		data->valid = 0;
-		cpu = data->id;
-		err = rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_STATUS,
-				   &eax, &edx);
-		if (!err) {
-			data->alarm = (eax >> 5) & 1;
-			data->temp = data->tjmax - (((eax >> 16)
-							& 0x7f) * 1000);
-			data->valid = 1;
-		} else
-			dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
-
-		data->last_updated = jiffies;
-	}
-
-	mutex_unlock(&data->update_lock);
-	return data;
-}
-
-static int get_tjmax(int cpu, struct device *dev)
-{
-	int default_tjmax = 100000;
-	int err;
-	u32 eax, edx;
-	u32 val;
-
-	/* IA32_TEMPERATURE_TARGET contains the TjMax value */
-	err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
-	if (!err) {
-		val = (eax >> 16) & 0xff;
-		if ((val > 80) && (val < 120)) {
-			dev_info(dev, "TjMax is %d C.\n", val);
-			return val * 1000;
-		}
-	}
-	dev_warn(dev, "Unable to read TjMax from CPU.\n");
-	return default_tjmax;
-}
-
-static int __devinit pkgtemp_probe(struct platform_device *pdev)
-{
-	struct pkgtemp_data *data;
-	int err;
-	u32 eax, edx;
-#ifdef CONFIG_SMP
-	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
-#endif
-
-	data = kzalloc(sizeof(struct pkgtemp_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		dev_err(&pdev->dev, "Out of memory\n");
-		goto exit;
-	}
-
-	data->id = pdev->id;
-#ifdef CONFIG_SMP
-	data->phys_proc_id = c->phys_proc_id;
-#endif
-	data->name = "pkgtemp";
-	mutex_init(&data->update_lock);
-
-	/* test if we can access the THERM_STATUS MSR */
-	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_PACKAGE_THERM_STATUS,
-				&eax, &edx);
-	if (err) {
-		dev_err(&pdev->dev,
-			"Unable to access THERM_STATUS MSR, giving up\n");
-		goto exit_free;
-	}
-
-	data->tjmax = get_tjmax(data->id, &pdev->dev);
-	platform_set_drvdata(pdev, data);
-
-	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
-				&eax, &edx);
-	if (err) {
-		dev_warn(&pdev->dev, "Unable to read"
-				" IA32_TEMPERATURE_TARGET MSR\n");
-	} else {
-		data->ttarget = data->tjmax - (((eax >> 8) & 0xff) * 1000);
-		err = device_create_file(&pdev->dev,
-				&sensor_dev_attr_temp1_max.dev_attr);
-		if (err)
-			goto exit_free;
-	}
-
-	err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group);
-	if (err)
-		goto exit_dev;
-
-	data->hwmon_dev = hwmon_device_register(&pdev->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		err = PTR_ERR(data->hwmon_dev);
-		dev_err(&pdev->dev, "Class registration failed (%d)\n",
-			err);
-		goto exit_class;
-	}
-
-	return 0;
-
-exit_class:
-	sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
-exit_dev:
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
-exit_free:
-	kfree(data);
-exit:
-	return err;
-}
-
-static int __devexit pkgtemp_remove(struct platform_device *pdev)
-{
-	struct pkgtemp_data *data = platform_get_drvdata(pdev);
-
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
-	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-	return 0;
-}
-
-static struct platform_driver pkgtemp_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = DRVNAME,
-	},
-	.probe = pkgtemp_probe,
-	.remove = __devexit_p(pkgtemp_remove),
-};
-
-struct pdev_entry {
-	struct list_head list;
-	struct platform_device *pdev;
-	unsigned int cpu;
-#ifdef CONFIG_SMP
-	u16 phys_proc_id;
-#endif
-};
-
-static LIST_HEAD(pdev_list);
-static DEFINE_MUTEX(pdev_list_mutex);
-
-static int __cpuinit pkgtemp_device_add(unsigned int cpu)
-{
-	int err;
-	struct platform_device *pdev;
-	struct pdev_entry *pdev_entry;
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
-
-	if (!cpu_has(c, X86_FEATURE_PTS))
-		return 0;
-
-	mutex_lock(&pdev_list_mutex);
-
-#ifdef CONFIG_SMP
-	/* Only keep the first entry in each package */
-	list_for_each_entry(pdev_entry, &pdev_list, list) {
-		if (c->phys_proc_id == pdev_entry->phys_proc_id) {
-			err = 0;        /* Not an error */
-			goto exit;
-		}
-	}
-#endif
-
-	pdev = platform_device_alloc(DRVNAME, cpu);
-	if (!pdev) {
-		err = -ENOMEM;
-		pr_err("Device allocation failed\n");
-		goto exit;
-	}
-
-	pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
-	if (!pdev_entry) {
-		err = -ENOMEM;
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		pr_err("Device addition failed (%d)\n", err);
-		goto exit_device_free;
-	}
-
-#ifdef CONFIG_SMP
-	pdev_entry->phys_proc_id = c->phys_proc_id;
-#endif
-	pdev_entry->pdev = pdev;
-	pdev_entry->cpu = cpu;
-	list_add_tail(&pdev_entry->list, &pdev_list);
-	mutex_unlock(&pdev_list_mutex);
-
-	return 0;
-
-exit_device_free:
-	kfree(pdev_entry);
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	mutex_unlock(&pdev_list_mutex);
-	return err;
-}
-
-static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
-{
-	struct pdev_entry *p;
-	unsigned int i;
-	int err;
-
-	mutex_lock(&pdev_list_mutex);
-	list_for_each_entry(p, &pdev_list, list) {
-		if (p->cpu != cpu)
-			continue;
-
-		platform_device_unregister(p->pdev);
-		list_del(&p->list);
-		mutex_unlock(&pdev_list_mutex);
-		kfree(p);
-		for_each_cpu(i, cpu_core_mask(cpu)) {
-			if (i != cpu) {
-				err = pkgtemp_device_add(i);
-				if (!err)
-					break;
-			}
-		}
-		return;
-	}
-	mutex_unlock(&pdev_list_mutex);
-}
-
-static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb,
-				 unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long) hcpu;
-
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_DOWN_FAILED:
-		pkgtemp_device_add(cpu);
-		break;
-	case CPU_DOWN_PREPARE:
-		pkgtemp_device_remove(cpu);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block pkgtemp_cpu_notifier __refdata = {
-	.notifier_call = pkgtemp_cpu_callback,
-};
-
-static int __init pkgtemp_init(void)
-{
-	int i, err = -ENODEV;
-
-	/* quick check if we run Intel */
-	if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
-		goto exit;
-
-	err = platform_driver_register(&pkgtemp_driver);
-	if (err)
-		goto exit;
-
-	for_each_online_cpu(i)
-		pkgtemp_device_add(i);
-
-#ifndef CONFIG_HOTPLUG_CPU
-	if (list_empty(&pdev_list)) {
-		err = -ENODEV;
-		goto exit_driver_unreg;
-	}
-#endif
-
-	register_hotcpu_notifier(&pkgtemp_cpu_notifier);
-	return 0;
-
-#ifndef CONFIG_HOTPLUG_CPU
-exit_driver_unreg:
-	platform_driver_unregister(&pkgtemp_driver);
-#endif
-exit:
-	return err;
-}
-
-static void __exit pkgtemp_exit(void)
-{
-	struct pdev_entry *p, *n;
-
-	unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
-	mutex_lock(&pdev_list_mutex);
-	list_for_each_entry_safe(p, n, &pdev_list, list) {
-		platform_device_unregister(p->pdev);
-		list_del(&p->list);
-		kfree(p);
-	}
-	mutex_unlock(&pdev_list_mutex);
-	platform_driver_unregister(&pkgtemp_driver);
-}
-
-MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
-MODULE_DESCRIPTION("Intel processor package temperature monitor");
-MODULE_LICENSE("GPL");
-
-module_init(pkgtemp_init)
-module_exit(pkgtemp_exit)
diff --git a/drivers/hwmon/pmbus.h b/drivers/hwmon/pmbus.h
index a81f7f2..50647ab 100644
--- a/drivers/hwmon/pmbus.h
+++ b/drivers/hwmon/pmbus.h
@@ -281,13 +281,11 @@
 
 	u32 func[PMBUS_PAGES];	/* Functionality, per page */
 	/*
-	 * The get_status function maps manufacturing specific status values
-	 * into PMBus standard status values.
-	 * This function is optional and only necessary if chip specific status
-	 * register values have to be mapped into standard PMBus status register
-	 * values.
+	 * The following functions map manufacturing specific register values
+	 * to PMBus standard register values. Specify only if mapping is
+	 * necessary.
 	 */
-	int (*get_status)(struct i2c_client *client, int page, int reg);
+	int (*read_byte_data)(struct i2c_client *client, int page, int reg);
 	/*
 	 * The identify function determines supported PMBus functionality.
 	 * This function is only necessary if a chip driver supports multiple
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c
index 196ffaf..98799ba 100644
--- a/drivers/hwmon/pmbus_core.c
+++ b/drivers/hwmon/pmbus_core.c
@@ -270,18 +270,22 @@
 }
 EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
 
-static int pmbus_get_status(struct i2c_client *client, int page, int reg)
+/*
+ * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
+ * a device specific mapping funcion exists and calls it if necessary.
+ */
+static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
 {
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	const struct pmbus_driver_info *info = data->info;
 	int status;
 
-	if (info->get_status) {
-		status = info->get_status(client, page, reg);
+	if (info->read_byte_data) {
+		status = info->read_byte_data(client, page, reg);
 		if (status != -ENODATA)
 			return status;
 	}
-	return  pmbus_read_byte_data(client, page, reg);
+	return pmbus_read_byte_data(client, page, reg);
 }
 
 static struct pmbus_data *pmbus_update_device(struct device *dev)
@@ -302,38 +306,41 @@
 			if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
 				continue;
 			data->status[PB_STATUS_VOUT_BASE + i]
-			  = pmbus_get_status(client, i, PMBUS_STATUS_VOUT);
+			  = _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_get_status(client, i, PMBUS_STATUS_IOUT);
+			  = _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_get_status(client, i,
-					     PMBUS_STATUS_TEMPERATURE);
+			  = _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_get_status(client, i, PMBUS_STATUS_FAN_12);
+			  = _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_get_status(client, i, PMBUS_STATUS_FAN_34);
+			  = _pmbus_read_byte_data(client, i,
+						  PMBUS_STATUS_FAN_34);
 		}
 
 		if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
 			data->status[PB_STATUS_INPUT_BASE]
-			  = pmbus_get_status(client, 0, PMBUS_STATUS_INPUT);
+			  = _pmbus_read_byte_data(client, 0,
+						  PMBUS_STATUS_INPUT);
 
 		for (i = 0; i < data->num_sensors; i++) {
 			struct pmbus_sensor *sensor = &data->sensors[i];
@@ -793,53 +800,6 @@
 	data->num_labels++;
 }
 
-static const int pmbus_temp_registers[] = {
-	PMBUS_READ_TEMPERATURE_1,
-	PMBUS_READ_TEMPERATURE_2,
-	PMBUS_READ_TEMPERATURE_3
-};
-
-static const int pmbus_temp_flags[] = {
-	PMBUS_HAVE_TEMP,
-	PMBUS_HAVE_TEMP2,
-	PMBUS_HAVE_TEMP3
-};
-
-static const int pmbus_fan_registers[] = {
-	PMBUS_READ_FAN_SPEED_1,
-	PMBUS_READ_FAN_SPEED_2,
-	PMBUS_READ_FAN_SPEED_3,
-	PMBUS_READ_FAN_SPEED_4
-};
-
-static const int pmbus_fan_config_registers[] = {
-	PMBUS_FAN_CONFIG_12,
-	PMBUS_FAN_CONFIG_12,
-	PMBUS_FAN_CONFIG_34,
-	PMBUS_FAN_CONFIG_34
-};
-
-static const int pmbus_fan_status_registers[] = {
-	PMBUS_STATUS_FAN_12,
-	PMBUS_STATUS_FAN_12,
-	PMBUS_STATUS_FAN_34,
-	PMBUS_STATUS_FAN_34
-};
-
-static const u32 pmbus_fan_flags[] = {
-	PMBUS_HAVE_FAN12,
-	PMBUS_HAVE_FAN12,
-	PMBUS_HAVE_FAN34,
-	PMBUS_HAVE_FAN34
-};
-
-static const u32 pmbus_fan_status_flags[] = {
-	PMBUS_HAVE_STATUS_FAN12,
-	PMBUS_HAVE_STATUS_FAN12,
-	PMBUS_HAVE_STATUS_FAN34,
-	PMBUS_HAVE_STATUS_FAN34
-};
-
 /*
  * Determine maximum number of sensors, booleans, and labels.
  * To keep things simple, only make a rough high estimate.
@@ -900,499 +860,431 @@
 /*
  * Search for attributes. Allocate sensors, booleans, and labels as needed.
  */
-static void pmbus_find_attributes(struct i2c_client *client,
-				  struct pmbus_data *data)
+
+/*
+ * The pmbus_limit_attr structure describes a single limit attribute
+ * and its associated alarm attribute.
+ */
+struct pmbus_limit_attr {
+	u8 reg;			/* Limit register */
+	const char *attr;	/* Attribute name */
+	const char *alarm;	/* Alarm attribute name */
+	u32 sbit;		/* Alarm attribute status bit */
+};
+
+/*
+ * The pmbus_sensor_attr structure describes one sensor attribute. This
+ * description includes a reference to the associated limit attributes.
+ */
+struct pmbus_sensor_attr {
+	u8 reg;				/* sensor register */
+	enum pmbus_sensor_classes class;/* sensor class */
+	const char *label;		/* sensor label */
+	bool paged;			/* true if paged sensor */
+	bool update;			/* true if update needed */
+	bool compare;			/* true if compare function needed */
+	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.
+ */
+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)
+{
+	const struct pmbus_limit_attr *l = attr->limit;
+	int nlimit = attr->nlimit;
+	bool have_alarm = false;
+	int i, cindex;
+
+	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,
+					 false);
+			if (info->func[page] & attr->sfunc) {
+				if (attr->compare) {
+					pmbus_add_boolean_cmp(data, name,
+						l->alarm, index,
+						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;
+			}
+		}
+		l++;
+	}
+	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)
+{
+	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);
+	if (attr->sfunc) {
+		have_alarm = pmbus_add_limit_attrs(client, data, info, name,
+						   index, page, cbase, attr);
+		/*
+		 * Add generic alarm attribute only if there are no individual
+		 * alarm attributes, and if there is a global alarm bit.
+		 */
+		if (!have_alarm && attr->gbit)
+			pmbus_add_boolean_reg(data, name, "alarm", index,
+					      PB_STATUS_BASE + page,
+					      attr->gbit);
+	}
+}
+
+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)
 {
 	const struct pmbus_driver_info *info = data->info;
-	int page, i0, i1, in_index;
+	int index, i;
 
-	/*
-	 * Input voltage sensors
-	 */
-	in_index = 1;
-	if (info->func[0] & PMBUS_HAVE_VIN) {
-		bool have_alarm = false;
+	index = 1;
+	for (i = 0; i < nattrs; i++) {
+		int page, pages;
 
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "in", in_index, "vin", 0);
-		pmbus_add_sensor(data, "in", "input", in_index, 0,
-				 PMBUS_READ_VIN, PSC_VOLTAGE_IN, true, true);
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_VIN_UV_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "min", in_index,
-					 0, PMBUS_VIN_UV_WARN_LIMIT,
-					 PSC_VOLTAGE_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
-				pmbus_add_boolean_reg(data, "in", "min_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_VOLTAGE_UV_WARNING);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_VIN_UV_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "lcrit", in_index,
-					 0, PMBUS_VIN_UV_FAULT_LIMIT,
-					 PSC_VOLTAGE_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
-				pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_VOLTAGE_UV_FAULT);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_VIN_OV_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "max", in_index,
-					 0, PMBUS_VIN_OV_WARN_LIMIT,
-					 PSC_VOLTAGE_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
-				pmbus_add_boolean_reg(data, "in", "max_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_VOLTAGE_OV_WARNING);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_VIN_OV_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "crit", in_index,
-					 0, PMBUS_VIN_OV_FAULT_LIMIT,
-					 PSC_VOLTAGE_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
-				pmbus_add_boolean_reg(data, "in", "crit_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_VOLTAGE_OV_FAULT);
-				have_alarm = true;
-			}
-		}
-		/*
-		 * Add generic alarm attribute only if there are no individual
-		 * attributes.
-		 */
-		if (!have_alarm)
-			pmbus_add_boolean_reg(data, "in", "alarm",
-					      in_index,
-					      PB_STATUS_BASE,
-					      PB_STATUS_VIN_UV);
-		in_index++;
-	}
-	if (info->func[0] & PMBUS_HAVE_VCAP) {
-		pmbus_add_label(data, "in", in_index, "vcap", 0);
-		pmbus_add_sensor(data, "in", "input", in_index, 0,
-				 PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true, true);
-		in_index++;
-	}
-
-	/*
-	 * Output voltage sensors
-	 */
-	for (page = 0; page < info->pages; page++) {
-		bool have_alarm = false;
-
-		if (!(info->func[page] & PMBUS_HAVE_VOUT))
-			continue;
-
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "in", in_index, "vout", page + 1);
-		pmbus_add_sensor(data, "in", "input", in_index, page,
-				 PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true, true);
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_VOUT_UV_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "min", in_index, page,
-					 PMBUS_VOUT_UV_WARN_LIMIT,
-					 PSC_VOLTAGE_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
-				pmbus_add_boolean_reg(data, "in", "min_alarm",
-						      in_index,
-						      PB_STATUS_VOUT_BASE +
-						      page,
-						      PB_VOLTAGE_UV_WARNING);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_VOUT_UV_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "lcrit", in_index, page,
-					 PMBUS_VOUT_UV_FAULT_LIMIT,
-					 PSC_VOLTAGE_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
-				pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
-						      in_index,
-						      PB_STATUS_VOUT_BASE +
-						      page,
-						      PB_VOLTAGE_UV_FAULT);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_VOUT_OV_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "max", in_index, page,
-					 PMBUS_VOUT_OV_WARN_LIMIT,
-					 PSC_VOLTAGE_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
-				pmbus_add_boolean_reg(data, "in", "max_alarm",
-						      in_index,
-						      PB_STATUS_VOUT_BASE +
-						      page,
-						      PB_VOLTAGE_OV_WARNING);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_VOUT_OV_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "in", "crit", in_index, page,
-					 PMBUS_VOUT_OV_FAULT_LIMIT,
-					 PSC_VOLTAGE_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
-				pmbus_add_boolean_reg(data, "in", "crit_alarm",
-						      in_index,
-						      PB_STATUS_VOUT_BASE +
-						      page,
-						      PB_VOLTAGE_OV_FAULT);
-				have_alarm = true;
-			}
-		}
-		/*
-		 * Add generic alarm attribute only if there are no individual
-		 * attributes.
-		 */
-		if (!have_alarm)
-			pmbus_add_boolean_reg(data, "in", "alarm",
-					      in_index,
-					      PB_STATUS_BASE + page,
-					      PB_STATUS_VOUT_OV);
-		in_index++;
-	}
-
-	/*
-	 * Current sensors
-	 */
-
-	/*
-	 * Input current sensors
-	 */
-	in_index = 1;
-	if (info->func[0] & PMBUS_HAVE_IIN) {
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "curr", in_index, "iin", 0);
-		pmbus_add_sensor(data, "curr", "input", in_index, 0,
-				 PMBUS_READ_IIN, PSC_CURRENT_IN, true, true);
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_IIN_OC_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "curr", "max", in_index,
-					 0, PMBUS_IIN_OC_WARN_LIMIT,
-					 PSC_CURRENT_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
-				pmbus_add_boolean_reg(data, "curr", "max_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_IIN_OC_WARNING);
-			}
-		}
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_IIN_OC_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "curr", "crit", in_index,
-					 0, PMBUS_IIN_OC_FAULT_LIMIT,
-					 PSC_CURRENT_IN, false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
-				pmbus_add_boolean_reg(data, "curr",
-						      "crit_alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_IIN_OC_FAULT);
-		}
-		in_index++;
-	}
-
-	/*
-	 * Output current sensors
-	 */
-	for (page = 0; page < info->pages; page++) {
-		bool have_alarm = false;
-
-		if (!(info->func[page] & PMBUS_HAVE_IOUT))
-			continue;
-
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "curr", in_index, "iout", page + 1);
-		pmbus_add_sensor(data, "curr", "input", in_index, page,
-				 PMBUS_READ_IOUT, PSC_CURRENT_OUT, true, true);
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_IOUT_OC_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "curr", "max", in_index, page,
-					 PMBUS_IOUT_OC_WARN_LIMIT,
-					 PSC_CURRENT_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
-				pmbus_add_boolean_reg(data, "curr", "max_alarm",
-						      in_index,
-						      PB_STATUS_IOUT_BASE +
-						      page, PB_IOUT_OC_WARNING);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_IOUT_UC_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "curr", "lcrit", in_index, page,
-					 PMBUS_IOUT_UC_FAULT_LIMIT,
-					 PSC_CURRENT_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
-				pmbus_add_boolean_reg(data, "curr",
-						      "lcrit_alarm",
-						      in_index,
-						      PB_STATUS_IOUT_BASE +
-						      page, PB_IOUT_UC_FAULT);
-				have_alarm = true;
-			}
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_IOUT_OC_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "curr", "crit", in_index, page,
-					 PMBUS_IOUT_OC_FAULT_LIMIT,
-					 PSC_CURRENT_OUT, false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
-				pmbus_add_boolean_reg(data, "curr",
-						      "crit_alarm",
-						      in_index,
-						      PB_STATUS_IOUT_BASE +
-						      page, PB_IOUT_OC_FAULT);
-				have_alarm = true;
-			}
-		}
-		/*
-		 * Add generic alarm attribute only if there are no individual
-		 * attributes.
-		 */
-		if (!have_alarm)
-			pmbus_add_boolean_reg(data, "curr", "alarm",
-					      in_index,
-					      PB_STATUS_BASE + page,
-					      PB_STATUS_IOUT_OC);
-		in_index++;
-	}
-
-	/*
-	 * Power sensors
-	 */
-	/*
-	 * Input Power sensors
-	 */
-	in_index = 1;
-	if (info->func[0] & PMBUS_HAVE_PIN) {
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "power", in_index, "pin", 0);
-		pmbus_add_sensor(data, "power", "input", in_index,
-				 0, PMBUS_READ_PIN, PSC_POWER, true, true);
-		if (pmbus_check_word_register(client, 0,
-					      PMBUS_PIN_OP_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "power", "max", in_index,
-					 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER,
-					 false, false);
-			if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
-				pmbus_add_boolean_reg(data, "power",
-						      "alarm",
-						      in_index,
-						      PB_STATUS_INPUT_BASE,
-						      PB_PIN_OP_WARNING);
-		}
-		in_index++;
-	}
-
-	/*
-	 * Output Power sensors
-	 */
-	for (page = 0; page < info->pages; page++) {
-		bool need_alarm = false;
-
-		if (!(info->func[page] & PMBUS_HAVE_POUT))
-			continue;
-
-		i0 = data->num_sensors;
-		pmbus_add_label(data, "power", in_index, "pout", page + 1);
-		pmbus_add_sensor(data, "power", "input", in_index, page,
-				 PMBUS_READ_POUT, PSC_POWER, true, true);
-		/*
-		 * Per hwmon sysfs API, power_cap is to be used to limit output
-		 * power.
-		 * We have two registers related to maximum output power,
-		 * PMBUS_POUT_MAX and PMBUS_POUT_OP_WARN_LIMIT.
-		 * PMBUS_POUT_MAX matches the powerX_cap attribute definition.
-		 * There is no attribute in the API to match
-		 * PMBUS_POUT_OP_WARN_LIMIT. We use powerX_max for now.
-		 */
-		if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "power", "cap", in_index, page,
-					 PMBUS_POUT_MAX, PSC_POWER,
-					 false, false);
-			need_alarm = true;
-		}
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_POUT_OP_WARN_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "power", "max", in_index, page,
-					 PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER,
-					 false, false);
-			need_alarm = true;
-		}
-		if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT))
-			pmbus_add_boolean_reg(data, "power", "alarm",
-					      in_index,
-					      PB_STATUS_IOUT_BASE + page,
-					      PB_POUT_OP_WARNING
-					      | PB_POWER_LIMITING);
-
-		if (pmbus_check_word_register(client, page,
-					      PMBUS_POUT_OP_FAULT_LIMIT)) {
-			i1 = data->num_sensors;
-			pmbus_add_sensor(data, "power", "crit", in_index, page,
-					 PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER,
-					 false, false);
-			if (info->func[page] & PMBUS_HAVE_STATUS_IOUT)
-				pmbus_add_boolean_reg(data, "power",
-						      "crit_alarm",
-						      in_index,
-						      PB_STATUS_IOUT_BASE
-						      + page,
-						      PB_POUT_OP_FAULT);
-		}
-		in_index++;
-	}
-
-	/*
-	 * Temperature sensors
-	 */
-	in_index = 1;
-	for (page = 0; page < info->pages; page++) {
-		int t;
-
-		for (t = 0; t < ARRAY_SIZE(pmbus_temp_registers); t++) {
-			bool have_alarm = false;
-
-			/*
-			 * A PMBus chip may support any combination of
-			 * temperature registers on any page. So we can not
-			 * abort after a failure to detect a register, but have
-			 * to continue checking for all registers on all pages.
-			 */
-			if (!(info->func[page] & pmbus_temp_flags[t]))
+		pages = attrs->paged ? info->pages : 1;
+		for (page = 0; page < pages; page++) {
+			if (!(info->func[page] & attrs->func))
 				continue;
-
-			if (!pmbus_check_word_register
-			    (client, page, pmbus_temp_registers[t]))
-				continue;
-
-			i0 = data->num_sensors;
-			pmbus_add_sensor(data, "temp", "input", in_index, page,
-					 pmbus_temp_registers[t],
-					 PSC_TEMPERATURE, true, true);
-
-			/*
-			 * PMBus provides only one status register for TEMP1-3.
-			 * Thus, we can not use the status register to determine
-			 * which of the three sensors actually caused an alarm.
-			 * Always compare current temperature against the limit
-			 * registers to determine alarm conditions for a
-			 * specific sensor.
-			 *
-			 * Since there is only one set of limit registers for
-			 * up to three temperature sensors, we need to update
-			 * all limit registers after the limit was changed for
-			 * one of the sensors. This ensures that correct limits
-			 * are reported for all temperature sensors.
-			 */
-			if (pmbus_check_word_register
-			    (client, page, PMBUS_UT_WARN_LIMIT)) {
-				i1 = data->num_sensors;
-				pmbus_add_sensor(data, "temp", "min", in_index,
-						 page, PMBUS_UT_WARN_LIMIT,
-						 PSC_TEMPERATURE, true, false);
-				if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
-					pmbus_add_boolean_cmp(data, "temp",
-						"min_alarm", in_index, i1, i0,
-						PB_STATUS_TEMP_BASE + page,
-						PB_TEMP_UT_WARNING);
-					have_alarm = true;
-				}
-			}
-			if (pmbus_check_word_register(client, page,
-						      PMBUS_UT_FAULT_LIMIT)) {
-				i1 = data->num_sensors;
-				pmbus_add_sensor(data, "temp", "lcrit",
-						 in_index, page,
-						 PMBUS_UT_FAULT_LIMIT,
-						 PSC_TEMPERATURE, true, false);
-				if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
-					pmbus_add_boolean_cmp(data, "temp",
-						"lcrit_alarm", in_index, i1, i0,
-						PB_STATUS_TEMP_BASE + page,
-						PB_TEMP_UT_FAULT);
-					have_alarm = true;
-				}
-			}
-			if (pmbus_check_word_register
-			    (client, page, PMBUS_OT_WARN_LIMIT)) {
-				i1 = data->num_sensors;
-				pmbus_add_sensor(data, "temp", "max", in_index,
-						 page, PMBUS_OT_WARN_LIMIT,
-						 PSC_TEMPERATURE, true, false);
-				if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
-					pmbus_add_boolean_cmp(data, "temp",
-						"max_alarm", in_index, i0, i1,
-						PB_STATUS_TEMP_BASE + page,
-						PB_TEMP_OT_WARNING);
-					have_alarm = true;
-				}
-			}
-			if (pmbus_check_word_register(client, page,
-						      PMBUS_OT_FAULT_LIMIT)) {
-				i1 = data->num_sensors;
-				pmbus_add_sensor(data, "temp", "crit", in_index,
-						 page, PMBUS_OT_FAULT_LIMIT,
-						 PSC_TEMPERATURE, true, false);
-				if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
-					pmbus_add_boolean_cmp(data, "temp",
-						"crit_alarm", in_index, i0, i1,
-						PB_STATUS_TEMP_BASE + page,
-						PB_TEMP_OT_FAULT);
-					have_alarm = true;
-				}
-			}
-			/*
-			 * Last resort - we were not able to create any alarm
-			 * registers. Report alarm for all sensors using the
-			 * status register temperature alarm bit.
-			 */
-			if (!have_alarm)
-				pmbus_add_boolean_reg(data, "temp", "alarm",
-						      in_index,
-						      PB_STATUS_BASE + page,
-						      PB_STATUS_TEMPERATURE);
-			in_index++;
+			pmbus_add_sensor_attrs_one(client, data, info, name,
+						   index, page, attrs);
+			index++;
 		}
+		attrs++;
 	}
+}
 
-	/*
-	 * Fans
-	 */
-	in_index = 1;
+static const struct pmbus_limit_attr vin_limit_attrs[] = {
+	{
+		.reg = PMBUS_VIN_UV_WARN_LIMIT,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_VOLTAGE_UV_WARNING,
+	}, {
+		.reg = PMBUS_VIN_UV_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_VOLTAGE_UV_FAULT,
+	}, {
+		.reg = PMBUS_VIN_OV_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_VOLTAGE_OV_WARNING,
+	}, {
+		.reg = PMBUS_VIN_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,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_VOLTAGE_UV_WARNING,
+	}, {
+		.reg = PMBUS_VOUT_UV_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_VOLTAGE_UV_FAULT,
+	}, {
+		.reg = PMBUS_VOUT_OV_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_VOLTAGE_OV_WARNING,
+	}, {
+		.reg = PMBUS_VOUT_OV_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_VOLTAGE_OV_FAULT,
+	}
+};
+
+static const struct pmbus_sensor_attr voltage_attributes[] = {
+	{
+		.reg = PMBUS_READ_VIN,
+		.class = PSC_VOLTAGE_IN,
+		.label = "vin",
+		.func = PMBUS_HAVE_VIN,
+		.sfunc = PMBUS_HAVE_STATUS_INPUT,
+		.sbase = PB_STATUS_INPUT_BASE,
+		.gbit = PB_STATUS_VIN_UV,
+		.limit = vin_limit_attrs,
+		.nlimit = ARRAY_SIZE(vin_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_VCAP,
+		.class = PSC_VOLTAGE_IN,
+		.label = "vcap",
+		.func = PMBUS_HAVE_VCAP,
+	}, {
+		.reg = PMBUS_READ_VOUT,
+		.class = PSC_VOLTAGE_OUT,
+		.label = "vout",
+		.paged = true,
+		.func = PMBUS_HAVE_VOUT,
+		.sfunc = PMBUS_HAVE_STATUS_VOUT,
+		.sbase = PB_STATUS_VOUT_BASE,
+		.gbit = PB_STATUS_VOUT_OV,
+		.limit = vout_limit_attrs,
+		.nlimit = ARRAY_SIZE(vout_limit_attrs),
+	}
+};
+
+/* Current attributes */
+
+static const struct pmbus_limit_attr iin_limit_attrs[] = {
+	{
+		.reg = PMBUS_IIN_OC_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_IIN_OC_WARNING,
+	}, {
+		.reg = PMBUS_IIN_OC_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_IIN_OC_FAULT,
+	}
+};
+
+static const struct pmbus_limit_attr iout_limit_attrs[] = {
+	{
+		.reg = PMBUS_IOUT_OC_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_IOUT_OC_WARNING,
+	}, {
+		.reg = PMBUS_IOUT_UC_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_IOUT_UC_FAULT,
+	}, {
+		.reg = PMBUS_IOUT_OC_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_IOUT_OC_FAULT,
+	}
+};
+
+static const struct pmbus_sensor_attr current_attributes[] = {
+	{
+		.reg = PMBUS_READ_IIN,
+		.class = PSC_CURRENT_IN,
+		.label = "iin",
+		.func = PMBUS_HAVE_IIN,
+		.sfunc = PMBUS_HAVE_STATUS_INPUT,
+		.sbase = PB_STATUS_INPUT_BASE,
+		.limit = iin_limit_attrs,
+		.nlimit = ARRAY_SIZE(iin_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_IOUT,
+		.class = PSC_CURRENT_OUT,
+		.label = "iout",
+		.paged = true,
+		.func = PMBUS_HAVE_IOUT,
+		.sfunc = PMBUS_HAVE_STATUS_IOUT,
+		.sbase = PB_STATUS_IOUT_BASE,
+		.gbit = PB_STATUS_IOUT_OC,
+		.limit = iout_limit_attrs,
+		.nlimit = ARRAY_SIZE(iout_limit_attrs),
+	}
+};
+
+/* Power attributes */
+
+static const struct pmbus_limit_attr pin_limit_attrs[] = {
+	{
+		.reg = PMBUS_PIN_OP_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "alarm",
+		.sbit = PB_PIN_OP_WARNING,
+	}
+};
+
+static const struct pmbus_limit_attr pout_limit_attrs[] = {
+	{
+		.reg = PMBUS_POUT_MAX,
+		.attr = "cap",
+		.alarm = "cap_alarm",
+		.sbit = PB_POWER_LIMITING,
+	}, {
+		.reg = PMBUS_POUT_OP_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_POUT_OP_WARNING,
+	}, {
+		.reg = PMBUS_POUT_OP_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_POUT_OP_FAULT,
+	}
+};
+
+static const struct pmbus_sensor_attr power_attributes[] = {
+	{
+		.reg = PMBUS_READ_PIN,
+		.class = PSC_POWER,
+		.label = "pin",
+		.func = PMBUS_HAVE_PIN,
+		.sfunc = PMBUS_HAVE_STATUS_INPUT,
+		.sbase = PB_STATUS_INPUT_BASE,
+		.limit = pin_limit_attrs,
+		.nlimit = ARRAY_SIZE(pin_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_POUT,
+		.class = PSC_POWER,
+		.label = "pout",
+		.paged = true,
+		.func = PMBUS_HAVE_POUT,
+		.sfunc = PMBUS_HAVE_STATUS_IOUT,
+		.sbase = PB_STATUS_IOUT_BASE,
+		.limit = pout_limit_attrs,
+		.nlimit = ARRAY_SIZE(pout_limit_attrs),
+	}
+};
+
+/* Temperature atributes */
+
+static const struct pmbus_limit_attr temp_limit_attrs[] = {
+	{
+		.reg = PMBUS_UT_WARN_LIMIT,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_TEMP_UT_WARNING,
+	}, {
+		.reg = PMBUS_UT_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_TEMP_UT_FAULT,
+	}, {
+		.reg = PMBUS_OT_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_TEMP_OT_WARNING,
+	}, {
+		.reg = PMBUS_OT_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_TEMP_OT_FAULT,
+	}
+};
+
+static const struct pmbus_sensor_attr temp_attributes[] = {
+	{
+		.reg = PMBUS_READ_TEMPERATURE_1,
+		.class = PSC_TEMPERATURE,
+		.paged = true,
+		.update = true,
+		.compare = true,
+		.func = PMBUS_HAVE_TEMP,
+		.sfunc = PMBUS_HAVE_STATUS_TEMP,
+		.sbase = PB_STATUS_TEMP_BASE,
+		.gbit = PB_STATUS_TEMPERATURE,
+		.limit = temp_limit_attrs,
+		.nlimit = ARRAY_SIZE(temp_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_TEMPERATURE_2,
+		.class = PSC_TEMPERATURE,
+		.paged = true,
+		.update = true,
+		.compare = true,
+		.func = PMBUS_HAVE_TEMP2,
+		.sfunc = PMBUS_HAVE_STATUS_TEMP,
+		.sbase = PB_STATUS_TEMP_BASE,
+		.gbit = PB_STATUS_TEMPERATURE,
+		.limit = temp_limit_attrs,
+		.nlimit = ARRAY_SIZE(temp_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_TEMPERATURE_3,
+		.class = PSC_TEMPERATURE,
+		.paged = true,
+		.update = true,
+		.compare = true,
+		.func = PMBUS_HAVE_TEMP3,
+		.sfunc = PMBUS_HAVE_STATUS_TEMP,
+		.sbase = PB_STATUS_TEMP_BASE,
+		.gbit = PB_STATUS_TEMPERATURE,
+		.limit = temp_limit_attrs,
+		.nlimit = ARRAY_SIZE(temp_limit_attrs),
+	}
+};
+
+static const int pmbus_fan_registers[] = {
+	PMBUS_READ_FAN_SPEED_1,
+	PMBUS_READ_FAN_SPEED_2,
+	PMBUS_READ_FAN_SPEED_3,
+	PMBUS_READ_FAN_SPEED_4
+};
+
+static const int pmbus_fan_config_registers[] = {
+	PMBUS_FAN_CONFIG_12,
+	PMBUS_FAN_CONFIG_12,
+	PMBUS_FAN_CONFIG_34,
+	PMBUS_FAN_CONFIG_34
+};
+
+static const int pmbus_fan_status_registers[] = {
+	PMBUS_STATUS_FAN_12,
+	PMBUS_STATUS_FAN_12,
+	PMBUS_STATUS_FAN_34,
+	PMBUS_STATUS_FAN_34
+};
+
+static const u32 pmbus_fan_flags[] = {
+	PMBUS_HAVE_FAN12,
+	PMBUS_HAVE_FAN12,
+	PMBUS_HAVE_FAN34,
+	PMBUS_HAVE_FAN34
+};
+
+static const u32 pmbus_fan_status_flags[] = {
+	PMBUS_HAVE_STATUS_FAN12,
+	PMBUS_HAVE_STATUS_FAN12,
+	PMBUS_HAVE_STATUS_FAN34,
+	PMBUS_HAVE_STATUS_FAN34
+};
+
+/* Fans */
+static void 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;
+
 	for (page = 0; page < info->pages; page++) {
 		int f;
 
@@ -1403,9 +1295,7 @@
 				break;
 
 			if (!pmbus_check_word_register(client, page,
-						       pmbus_fan_registers[f])
-			    || !pmbus_check_byte_register(client, page,
-						pmbus_fan_config_registers[f]))
+						       pmbus_fan_registers[f]))
 				break;
 
 			/*
@@ -1413,14 +1303,13 @@
 			 * Each fan configuration register covers multiple fans,
 			 * so we have to do some magic.
 			 */
-			regval = pmbus_read_byte_data(client, page,
+			regval = _pmbus_read_byte_data(client, page,
 				pmbus_fan_config_registers[f]);
 			if (regval < 0 ||
 			    (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
 				continue;
 
-			i0 = data->num_sensors;
-			pmbus_add_sensor(data, "fan", "input", in_index, page,
+			pmbus_add_sensor(data, "fan", "input", index, page,
 					 pmbus_fan_registers[f], PSC_FAN, true,
 					 true);
 
@@ -1438,17 +1327,40 @@
 				else
 					base = PB_STATUS_FAN_BASE + page;
 				pmbus_add_boolean_reg(data, "fan", "alarm",
-					in_index, base,
+					index, base,
 					PB_FAN_FAN1_WARNING >> (f & 1));
 				pmbus_add_boolean_reg(data, "fan", "fault",
-					in_index, base,
+					index, base,
 					PB_FAN_FAN1_FAULT >> (f & 1));
 			}
-			in_index++;
+			index++;
 		}
 	}
 }
 
+static void pmbus_find_attributes(struct i2c_client *client,
+				  struct pmbus_data *data)
+{
+	/* Voltage sensors */
+	pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+			       ARRAY_SIZE(voltage_attributes));
+
+	/* Current sensors */
+	pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+			       ARRAY_SIZE(current_attributes));
+
+	/* Power sensors */
+	pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+			       ARRAY_SIZE(power_attributes));
+
+	/* Temperature sensors */
+	pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+			       ARRAY_SIZE(temp_attributes));
+
+	/* Fans */
+	pmbus_add_fan_attributes(client, data);
+}
+
 /*
  * Identify chip parameters.
  * This function is called for all chips.
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index f4e617a..cf4330b 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1,6 +1,10 @@
 /*
  * sht15.c - support for the SHT15 Temperature and Humidity Sensor
  *
+ * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ *          Jerome Oufella <jerome.oufella@savoirfairelinux.com>
+ *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
  * Copyright (c) 2009 Jonathan Cameron
  *
  * Copyright (c) 2007 Wouter Horre
@@ -9,16 +13,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * Currently ignoring checksum on readings.
- * Default resolution only (14bit temp, 12bit humidity)
- * Ignoring battery status.
- * Heater not enabled.
- * Timings are all conservative.
- *
- * Data sheet available (1/2009) at
- * http://www.sensirion.ch/en/pdf/product_information/Datasheet-humidity-sensor-SHT1x.pdf
- *
- * Regulator supply name = vcc
+ * For further information, see the Documentation/hwmon/sht15 file.
  */
 
 #include <linux/interrupt.h>
@@ -39,17 +34,31 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 
-#define SHT15_MEASURE_TEMP	3
-#define SHT15_MEASURE_RH	5
+/* Commands */
+#define SHT15_MEASURE_TEMP		0x03
+#define SHT15_MEASURE_RH		0x05
+#define SHT15_WRITE_STATUS		0x06
+#define SHT15_READ_STATUS		0x07
+#define SHT15_SOFT_RESET		0x1E
 
-#define SHT15_READING_NOTHING	0
-#define SHT15_READING_TEMP	1
-#define SHT15_READING_HUMID	2
+/* Min timings */
+#define SHT15_TSCKL			100	/* (nsecs) clock low */
+#define SHT15_TSCKH			100	/* (nsecs) clock high */
+#define SHT15_TSU			150	/* (nsecs) data setup time */
+#define SHT15_TSRST			11	/* (msecs) soft reset time */
 
-/* Min timings in nsecs */
-#define SHT15_TSCKL		100	/* clock low */
-#define SHT15_TSCKH		100	/* clock high */
-#define SHT15_TSU		150	/* data setup time */
+/* Status Register Bits */
+#define SHT15_STATUS_LOW_RESOLUTION	0x01
+#define SHT15_STATUS_NO_OTP_RELOAD	0x02
+#define SHT15_STATUS_HEATER		0x04
+#define SHT15_STATUS_LOW_BATTERY	0x40
+
+/* Actions the driver may be doing */
+enum sht15_state {
+	SHT15_READING_NOTHING,
+	SHT15_READING_TEMP,
+	SHT15_READING_HUMID
+};
 
 /**
  * struct sht15_temppair - elements of voltage dependent temp calc
@@ -61,9 +70,7 @@
 	int d1;
 };
 
-/* Table 9 from data sheet - relates temperature calculation
- * to supply voltage.
- */
+/* Table 9 from datasheet - relates temperature calculation to supply voltage */
 static const struct sht15_temppair temppoints[] = {
 	{ 2500000, -39400 },
 	{ 3000000, -39600 },
@@ -72,29 +79,70 @@
 	{ 5000000, -40100 },
 };
 
+/* Table from CRC datasheet, section 2.4 */
+static const u8 sht15_crc8_table[] = {
+	0,	49,	98,	83,	196,	245,	166,	151,
+	185,	136,	219,	234,	125,	76,	31,	46,
+	67,	114,	33,	16,	135,	182,	229,	212,
+	250,	203,	152,	169,	62,	15,	92,	109,
+	134,	183,	228,	213,	66,	115,	32,	17,
+	63,	14,	93,	108,	251,	202,	153,	168,
+	197,	244,	167,	150,	1,	48,	99,	82,
+	124,	77,	30,	47,	184,	137,	218,	235,
+	61,	12,	95,	110,	249,	200,	155,	170,
+	132,	181,	230,	215,	64,	113,	34,	19,
+	126,	79,	28,	45,	186,	139,	216,	233,
+	199,	246,	165,	148,	3,	50,	97,	80,
+	187,	138,	217,	232,	127,	78,	29,	44,
+	2,	51,	96,	81,	198,	247,	164,	149,
+	248,	201,	154,	171,	60,	13,	94,	111,
+	65,	112,	35,	18,	133,	180,	231,	214,
+	122,	75,	24,	41,	190,	143,	220,	237,
+	195,	242,	161,	144,	7,	54,	101,	84,
+	57,	8,	91,	106,	253,	204,	159,	174,
+	128,	177,	226,	211,	68,	117,	38,	23,
+	252,	205,	158,	175,	56,	9,	90,	107,
+	69,	116,	39,	22,	129,	176,	227,	210,
+	191,	142,	221,	236,	123,	74,	25,	40,
+	6,	55,	100,	85,	194,	243,	160,	145,
+	71,	118,	37,	20,	131,	178,	225,	208,
+	254,	207,	156,	173,	58,	11,	88,	105,
+	4,	53,	102,	87,	192,	241,	162,	147,
+	189,	140,	223,	238,	121,	72,	27,	42,
+	193,	240,	163,	146,	5,	52,	103,	86,
+	120,	73,	26,	43,	188,	141,	222,	239,
+	130,	179,	224,	209,	70,	119,	36,	21,
+	59,	10,	89,	104,	255,	206,	157,	172
+};
+
 /**
  * struct sht15_data - device instance specific data
- * @pdata:	platform data (gpio's etc)
- * @read_work:	bh of interrupt handler
- * @wait_queue:	wait queue for getting values from device
- * @val_temp:	last temperature value read from device
- * @val_humid: 	last humidity value read from device
- * @flag:	status flag used to identify what the last request was
- * @valid:	are the current stored values valid (start condition)
- * @last_updat:	time of last update
- * @read_lock:	mutex to ensure only one read in progress
- *		at a time.
- * @dev:	associate device structure
- * @hwmon_dev:	device associated with hwmon subsystem
- * @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 regulator consumer if available
- * @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
- * @interrupt_handled:	flag used to indicate a hander has been scheduled
+ * @pdata:		platform data (gpio's etc).
+ * @read_work:		bh of interrupt handler.
+ * @wait_queue:		wait queue for getting values from device.
+ * @val_temp:		last temperature value read from device.
+ * @val_humid:		last humidity value read from device.
+ * @val_status:		last status register value read from device.
+ * @checksum_ok:	last value read from the device passed CRC validation.
+ * @checksumming:	flag used to enable the data validation with CRC.
+ * @state:		state identifying the action the driver is doing.
+ * @measurements_valid:	are the current stored measures valid (start condition).
+ * @status_valid:	is the current stored status valid (start condition).
+ * @last_measurement:	time of last measure.
+ * @last_status:	time of last status reading.
+ * @read_lock:		mutex to ensure only one read in progress at a time.
+ * @dev:		associate device structure.
+ * @hwmon_dev:		device associated with hwmon subsystem.
+ * @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
+ *                      regulator consumer if available.
+ * @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.
+ * @interrupt_handled:	flag used to indicate a handler has been scheduled.
  */
 struct sht15_data {
 	struct sht15_platform_data	*pdata;
@@ -102,21 +150,60 @@
 	wait_queue_head_t		wait_queue;
 	uint16_t			val_temp;
 	uint16_t			val_humid;
-	u8				flag;
-	u8				valid;
-	unsigned long			last_updat;
+	u8				val_status;
+	bool				checksum_ok;
+	bool				checksumming;
+	enum sht15_state		state;
+	bool				measurements_valid;
+	bool				status_valid;
+	unsigned long			last_measurement;
+	unsigned long			last_status;
 	struct mutex			read_lock;
 	struct device			*dev;
 	struct device			*hwmon_dev;
 	struct regulator		*reg;
 	struct notifier_block		nb;
 	int				supply_uV;
-	int				supply_uV_valid;
+	bool				supply_uV_valid;
 	struct work_struct		update_supply_work;
 	atomic_t			interrupt_handled;
 };
 
 /**
+ * sht15_reverse() - reverse a byte
+ * @byte:    byte to reverse.
+ */
+static u8 sht15_reverse(u8 byte)
+{
+	u8 i, c;
+
+	for (c = 0, i = 0; i < 8; i++)
+		c |= (!!(byte & (1 << i))) << (7 - i);
+	return c;
+}
+
+/**
+ * sht15_crc8() - compute crc8
+ * @data:	sht15 specific data.
+ * @value:	sht15 retrieved data.
+ *
+ * This implements section 2 of the CRC datasheet.
+ */
+static u8 sht15_crc8(struct sht15_data *data,
+		const u8 *value,
+		int len)
+{
+	u8 crc = sht15_reverse(data->val_status & 0x0F);
+
+	while (len--) {
+		crc = sht15_crc8_table[*value ^ crc];
+		value++;
+	}
+
+	return crc;
+}
+
+/**
  * sht15_connection_reset() - reset the comms interface
  * @data:	sht15 specific data
  *
@@ -125,6 +212,7 @@
 static void sht15_connection_reset(struct sht15_data *data)
 {
 	int i;
+
 	gpio_direction_output(data->pdata->gpio_data, 1);
 	ndelay(SHT15_TSCKL);
 	gpio_set_value(data->pdata->gpio_sck, 0);
@@ -136,14 +224,14 @@
 		ndelay(SHT15_TSCKL);
 	}
 }
+
 /**
  * sht15_send_bit() - send an individual bit to the device
  * @data:	device state data
  * @val:	value of bit to be sent
- **/
+ */
 static inline void sht15_send_bit(struct sht15_data *data, int val)
 {
-
 	gpio_set_value(data->pdata->gpio_data, val);
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_sck, 1);
@@ -154,12 +242,12 @@
 
 /**
  * sht15_transmission_start() - specific sequence for new transmission
- *
  * @data:	device state data
+ *
  * Timings for this are not documented on the data sheet, so very
  * conservative ones used in implementation. This implements
  * figure 12 on the data sheet.
- **/
+ */
 static void sht15_transmission_start(struct sht15_data *data)
 {
 	/* ensure data is high and output */
@@ -180,23 +268,26 @@
 	gpio_set_value(data->pdata->gpio_sck, 0);
 	ndelay(SHT15_TSCKL);
 }
+
 /**
  * sht15_send_byte() - send a single byte to the device
  * @data:	device state
  * @byte:	value to be sent
- **/
+ */
 static void sht15_send_byte(struct sht15_data *data, u8 byte)
 {
 	int i;
+
 	for (i = 0; i < 8; i++) {
 		sht15_send_bit(data, !!(byte & 0x80));
 		byte <<= 1;
 	}
 }
+
 /**
  * sht15_wait_for_response() - checks for ack from device
  * @data:	device state
- **/
+ */
 static int sht15_wait_for_response(struct sht15_data *data)
 {
 	gpio_direction_input(data->pdata->gpio_data);
@@ -220,27 +311,199 @@
  *
  * On entry, sck is output low, data is output pull high
  * and the interrupt disabled.
- **/
+ */
 static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
 {
 	int ret = 0;
+
 	sht15_transmission_start(data);
 	sht15_send_byte(data, cmd);
 	ret = sht15_wait_for_response(data);
 	return ret;
 }
+
 /**
- * sht15_update_single_val() - get a new value from device
+ * sht15_soft_reset() - send a soft reset command
+ * @data:	sht15 specific data.
+ *
+ * As described in section 3.2 of the datasheet.
+ */
+static int sht15_soft_reset(struct sht15_data *data)
+{
+	int ret;
+
+	ret = sht15_send_cmd(data, SHT15_SOFT_RESET);
+	if (ret)
+		return ret;
+	msleep(SHT15_TSRST);
+	/* device resets default hardware status register value */
+	data->val_status = 0;
+
+	return ret;
+}
+
+/**
+ * sht15_ack() - send a ack
+ * @data:	sht15 specific 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)
+{
+	gpio_direction_output(data->pdata->gpio_data, 0);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_data, 1);
+
+	gpio_direction_input(data->pdata->gpio_data);
+}
+
+/**
+ * sht15_end_transmission() - notify device of end of transmission
+ * @data:	device state.
+ *
+ * This is basically a NAK (single clock pulse, data high).
+ */
+static void sht15_end_transmission(struct sht15_data *data)
+{
+	gpio_direction_output(data->pdata->gpio_data, 1);
+	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);
+}
+
+/**
+ * sht15_read_byte() - Read a byte back from the device
+ * @data:	device state.
+ */
+static u8 sht15_read_byte(struct sht15_data *data)
+{
+	int i;
+	u8 byte = 0;
+
+	for (i = 0; i < 8; ++i) {
+		byte <<= 1;
+		gpio_set_value(data->pdata->gpio_sck, 1);
+		ndelay(SHT15_TSCKH);
+		byte |= !!gpio_get_value(data->pdata->gpio_data);
+		gpio_set_value(data->pdata->gpio_sck, 0);
+		ndelay(SHT15_TSCKL);
+	}
+	return byte;
+}
+
+/**
+ * sht15_send_status() - write the status register byte
+ * @data:	sht15 specific data.
+ * @status:	the byte to set the status register with.
+ *
+ * As described in figure 14 and table 5 of the datasheet.
+ */
+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);
+	ndelay(SHT15_TSU);
+	sht15_send_byte(data, status);
+	ret = sht15_wait_for_response(data);
+	if (ret)
+		return ret;
+
+	data->val_status = status;
+	return 0;
+}
+
+/**
+ * sht15_update_status() - get updated status register from device if too old
+ * @data:	device instance specific data.
+ *
+ * As described in figure 15 and table 5 of the datasheet.
+ */
+static int sht15_update_status(struct sht15_data *data)
+{
+	int ret = 0;
+	u8 status;
+	u8 previous_config;
+	u8 dev_checksum = 0;
+	u8 checksum_vals[2];
+	int timeout = HZ;
+
+	mutex_lock(&data->read_lock);
+	if (time_after(jiffies, data->last_status + timeout)
+			|| !data->status_valid) {
+		ret = sht15_send_cmd(data, SHT15_READ_STATUS);
+		if (ret)
+			goto error_ret;
+		status = sht15_read_byte(data);
+
+		if (data->checksumming) {
+			sht15_ack(data);
+			dev_checksum = sht15_reverse(sht15_read_byte(data));
+			checksum_vals[0] = SHT15_READ_STATUS;
+			checksum_vals[1] = status;
+			data->checksum_ok = (sht15_crc8(data, checksum_vals, 2)
+					== dev_checksum);
+		}
+
+		sht15_end_transmission(data);
+
+		/*
+		 * Perform checksum validation on the received data.
+		 * Specification mentions that in case a checksum verification
+		 * fails, a soft reset command must be sent to the device.
+		 */
+		if (data->checksumming && !data->checksum_ok) {
+			previous_config = data->val_status & 0x07;
+			ret = sht15_soft_reset(data);
+			if (ret)
+				goto error_ret;
+			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;
+				}
+			}
+			ret = -EAGAIN;
+			goto error_ret;
+		}
+
+		data->val_status = status;
+		data->status_valid = true;
+		data->last_status = jiffies;
+	}
+error_ret:
+	mutex_unlock(&data->read_lock);
+
+	return ret;
+}
+
+/**
+ * sht15_measurement() - get a new value from device
  * @data:		device instance specific data
  * @command:		command sent to request value
  * @timeout_msecs:	timeout after which comms are assumed
  *			to have failed are reset.
- **/
-static inline int sht15_update_single_val(struct sht15_data *data,
-					  int command,
-					  int timeout_msecs)
+ */
+static int sht15_measurement(struct sht15_data *data,
+			     int command,
+			     int timeout_msecs)
 {
 	int ret;
+	u8 previous_config;
+
 	ret = sht15_send_cmd(data, command);
 	if (ret)
 		return ret;
@@ -256,38 +519,61 @@
 			schedule_work(&data->read_work);
 	}
 	ret = wait_event_timeout(data->wait_queue,
-				 (data->flag == SHT15_READING_NOTHING),
+				 (data->state == SHT15_READING_NOTHING),
 				 msecs_to_jiffies(timeout_msecs));
 	if (ret == 0) {/* timeout occurred */
 		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
 		sht15_connection_reset(data);
 		return -ETIME;
 	}
+
+	/*
+	 *  Perform checksum validation on the received data.
+	 *  Specification mentions that in case a checksum verification fails,
+	 *  a soft reset command must be sent to the device.
+	 */
+	if (data->checksumming && !data->checksum_ok) {
+		previous_config = data->val_status & 0x07;
+		ret = sht15_soft_reset(data);
+		if (ret)
+			return ret;
+		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");
+				return ret;
+			}
+		}
+		return -EAGAIN;
+	}
+
 	return 0;
 }
 
 /**
- * sht15_update_vals() - get updated readings from device if too old
+ * sht15_update_measurements() - get updated measures from device if too old
  * @data:	device state
- **/
-static int sht15_update_vals(struct sht15_data *data)
+ */
+static int sht15_update_measurements(struct sht15_data *data)
 {
 	int ret = 0;
 	int timeout = HZ;
 
 	mutex_lock(&data->read_lock);
-	if (time_after(jiffies, data->last_updat + timeout)
-	    || !data->valid) {
-		data->flag = SHT15_READING_HUMID;
-		ret = sht15_update_single_val(data, SHT15_MEASURE_RH, 160);
+	if (time_after(jiffies, data->last_measurement + timeout)
+	    || !data->measurements_valid) {
+		data->state = SHT15_READING_HUMID;
+		ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
 		if (ret)
 			goto error_ret;
-		data->flag = SHT15_READING_TEMP;
-		ret = sht15_update_single_val(data, SHT15_MEASURE_TEMP, 400);
+		data->state = SHT15_READING_TEMP;
+		ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
 		if (ret)
 			goto error_ret;
-		data->valid = 1;
-		data->last_updat = jiffies;
+		data->measurements_valid = true;
+		data->last_measurement = jiffies;
 	}
 error_ret:
 	mutex_unlock(&data->read_lock);
@@ -300,10 +586,11 @@
  * @data:	device state
  *
  * As per section 4.3 of the data sheet.
- **/
+ */
 static inline int sht15_calc_temp(struct sht15_data *data)
 {
 	int d1 = temppoints[0].d1;
+	int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
 	int i;
 
 	for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
@@ -316,7 +603,7 @@
 			break;
 		}
 
-	return data->val_temp*10 + d1;
+	return data->val_temp * d2 + d1;
 }
 
 /**
@@ -325,23 +612,102 @@
  *
  * This is the temperature compensated version as per section 4.2 of
  * the data sheet.
- **/
+ *
+ * The sensor is assumed to be V3, which is compatible with V4.
+ * Humidity conversion coefficients are shown in table 7 of the datasheet.
+ */
 static inline int sht15_calc_humid(struct sht15_data *data)
 {
-	int RHlinear; /* milli percent */
+	int rh_linear; /* milli percent */
 	int temp = sht15_calc_temp(data);
-
+	int c2, c3;
+	int t2;
 	const int c1 = -4;
-	const int c2 = 40500; /* x 10 ^ -6 */
-	const int c3 = -28; /* x 10 ^ -7 */
 
-	RHlinear = c1*1000
-		+ c2 * data->val_humid/1000
+	if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
+		c2 = 648000; /* x 10 ^ -6 */
+		c3 = -7200;  /* x 10 ^ -7 */
+		t2 = 1280;
+	} else {
+		c2 = 40500;  /* x 10 ^ -6 */
+		c3 = -28;    /* x 10 ^ -7 */
+		t2 = 80;
+	}
+
+	rh_linear = c1 * 1000
+		+ c2 * data->val_humid / 1000
 		+ (data->val_humid * data->val_humid * c3) / 10000;
-	return (temp - 25000) * (10000 + 80 * data->val_humid)
-		/ 1000000 + RHlinear;
+	return (temp - 25000) * (10000 + t2 * data->val_humid)
+		/ 1000000 + rh_linear;
 }
 
+/**
+ * sht15_show_status() - show status information in sysfs
+ * @dev:	device.
+ * @attr:	device attribute.
+ * @buf:	sysfs buffer where information is written to.
+ *
+ * Will be called on read access to temp1_fault, humidity1_fault
+ * and heater_enable sysfs attributes.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht15_show_status(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	int ret;
+	struct sht15_data *data = dev_get_drvdata(dev);
+	u8 bit = to_sensor_dev_attr(attr)->index;
+
+	ret = sht15_update_status(data);
+
+	return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
+}
+
+/**
+ * sht15_store_heater() - change heater state via sysfs
+ * @dev:	device.
+ * @attr:	device attribute.
+ * @buf:	sysfs buffer to read the new heater state from.
+ * @count:	length of the data.
+ *
+ * Will be called on read access to heater_enable sysfs attribute.
+ * Returns number of bytes actually decoded, negative errno on error.
+ */
+static ssize_t sht15_store_heater(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret;
+	struct sht15_data *data = dev_get_drvdata(dev);
+	long value;
+	u8 status;
+
+	if (strict_strtol(buf, 10, &value))
+		return -EINVAL;
+
+	mutex_lock(&data->read_lock);
+	status = data->val_status & 0x07;
+	if (!!value)
+		status |= SHT15_STATUS_HEATER;
+	else
+		status &= ~SHT15_STATUS_HEATER;
+
+	ret = sht15_send_status(data, status);
+	mutex_unlock(&data->read_lock);
+
+	return ret ? ret : count;
+}
+
+/**
+ * sht15_show_temp() - show temperature measurement value in sysfs
+ * @dev:	device.
+ * @attr:	device attribute.
+ * @buf:	sysfs buffer where measurement values are written to.
+ *
+ * Will be called on read access to temp1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
 static ssize_t sht15_show_temp(struct device *dev,
 			       struct device_attribute *attr,
 			       char *buf)
@@ -350,12 +716,21 @@
 	struct sht15_data *data = dev_get_drvdata(dev);
 
 	/* Technically no need to read humidity as well */
-	ret = sht15_update_vals(data);
+	ret = sht15_update_measurements(data);
 
 	return ret ? ret : sprintf(buf, "%d\n",
 				   sht15_calc_temp(data));
 }
 
+/**
+ * sht15_show_humidity() - show humidity measurement value in sysfs
+ * @dev:	device.
+ * @attr:	device attribute.
+ * @buf:	sysfs buffer where measurement values are written to.
+ *
+ * Will be called on read access to humidity1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
 static ssize_t sht15_show_humidity(struct device *dev,
 				   struct device_attribute *attr,
 				   char *buf)
@@ -363,11 +738,11 @@
 	int ret;
 	struct sht15_data *data = dev_get_drvdata(dev);
 
-	ret = sht15_update_vals(data);
+	ret = sht15_update_measurements(data);
 
 	return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
+}
 
-};
 static ssize_t show_name(struct device *dev,
 			 struct device_attribute *attr,
 			 char *buf)
@@ -376,16 +751,23 @@
 	return sprintf(buf, "%s\n", pdev->name);
 }
 
-static SENSOR_DEVICE_ATTR(temp1_input,
-			  S_IRUGO, sht15_show_temp,
-			  NULL, 0);
-static SENSOR_DEVICE_ATTR(humidity1_input,
-			  S_IRUGO, sht15_show_humidity,
-			  NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+			  sht15_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
+			  sht15_show_humidity, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL,
+			  SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL,
+			  SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status,
+			  sht15_store_heater, SHT15_STATUS_HEATER);
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 static struct attribute *sht15_attrs[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_humidity1_fault.dev_attr.attr,
+	&sensor_dev_attr_heater_enable.dev_attr.attr,
 	&dev_attr_name.attr,
 	NULL,
 };
@@ -397,59 +779,31 @@
 static irqreturn_t sht15_interrupt_fired(int irq, void *d)
 {
 	struct sht15_data *data = d;
+
 	/* First disable the interrupt */
 	disable_irq_nosync(irq);
 	atomic_inc(&data->interrupt_handled);
 	/* Then schedule a reading work struct */
-	if (data->flag != SHT15_READING_NOTHING)
+	if (data->state != SHT15_READING_NOTHING)
 		schedule_work(&data->read_work);
 	return IRQ_HANDLED;
 }
 
-/* Each byte of data is acknowledged by pulling the data line
- * low for one clock pulse.
- */
-static void sht15_ack(struct sht15_data *data)
-{
-	gpio_direction_output(data->pdata->gpio_data, 0);
-	ndelay(SHT15_TSU);
-	gpio_set_value(data->pdata->gpio_sck, 1);
-	ndelay(SHT15_TSU);
-	gpio_set_value(data->pdata->gpio_sck, 0);
-	ndelay(SHT15_TSU);
-	gpio_set_value(data->pdata->gpio_data, 1);
-
-	gpio_direction_input(data->pdata->gpio_data);
-}
-/**
- * sht15_end_transmission() - notify device of end of transmission
- * @data:	device state
- *
- * This is basically a NAK. (single clock pulse, data high)
- **/
-static void sht15_end_transmission(struct sht15_data *data)
-{
-	gpio_direction_output(data->pdata->gpio_data, 1);
-	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);
-}
-
 static void sht15_bh_read_data(struct work_struct *work_s)
 {
-	int i;
 	uint16_t val = 0;
+	u8 dev_checksum = 0;
+	u8 checksum_vals[3];
 	struct sht15_data *data
 		= container_of(work_s, struct sht15_data,
 			       read_work);
+
 	/* Firstly, verify the line is low */
 	if (gpio_get_value(data->pdata->gpio_data)) {
-		/* If not, then start the interrupt again - care
-		   here as could have gone low in meantime so verify
-		   it hasn't!
-		*/
+		/*
+		 * If not, then start the interrupt again - care here as could
+		 * have gone low in meantime so verify it hasn't!
+		 */
 		atomic_set(&data->interrupt_handled, 0);
 		enable_irq(gpio_to_irq(data->pdata->gpio_data));
 		/* If still not occurred or another handler has been scheduled */
@@ -457,30 +811,43 @@
 		    || atomic_read(&data->interrupt_handled))
 			return;
 	}
+
 	/* Read the data back from the device */
-	for (i = 0; i < 16; ++i) {
-		val <<= 1;
-		gpio_set_value(data->pdata->gpio_sck, 1);
-		ndelay(SHT15_TSCKH);
-		val |= !!gpio_get_value(data->pdata->gpio_data);
-		gpio_set_value(data->pdata->gpio_sck, 0);
-		ndelay(SHT15_TSCKL);
-		if (i == 7)
-			sht15_ack(data);
+	val = sht15_read_byte(data);
+	val <<= 8;
+	sht15_ack(data);
+	val |= sht15_read_byte(data);
+
+	if (data->checksumming) {
+		/*
+		 * Ask the device for a checksum and read it back.
+		 * Note: the device sends the checksum byte reversed.
+		 */
+		sht15_ack(data);
+		dev_checksum = sht15_reverse(sht15_read_byte(data));
+		checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
+			SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
+		checksum_vals[1] = (u8) (val >> 8);
+		checksum_vals[2] = (u8) val;
+		data->checksum_ok
+			= (sht15_crc8(data, checksum_vals, 3) == dev_checksum);
 	}
+
 	/* Tell the device we are done */
 	sht15_end_transmission(data);
 
-	switch (data->flag) {
+	switch (data->state) {
 	case SHT15_READING_TEMP:
 		data->val_temp = val;
 		break;
 	case SHT15_READING_HUMID:
 		data->val_humid = val;
 		break;
+	default:
+		break;
 	}
 
-	data->flag = SHT15_READING_NOTHING;
+	data->state = SHT15_READING_NOTHING;
 	wake_up(&data->wait_queue);
 }
 
@@ -500,10 +867,10 @@
  *
  * Note that as the notification code holds the regulator lock, we have
  * to schedule an update of the supply voltage rather than getting it directly.
- **/
+ */
 static int sht15_invalidate_voltage(struct notifier_block *nb,
-				unsigned long event,
-				void *ignored)
+				    unsigned long event,
+				    void *ignored)
 {
 	struct sht15_data *data = container_of(nb, struct sht15_data, nb);
 
@@ -518,10 +885,11 @@
 {
 	int ret = 0;
 	struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+	u8 status = 0;
 
 	if (!data) {
 		ret = -ENOMEM;
-		dev_err(&pdev->dev, "kzalloc failed");
+		dev_err(&pdev->dev, "kzalloc failed\n");
 		goto error_ret;
 	}
 
@@ -533,13 +901,22 @@
 	init_waitqueue_head(&data->wait_queue);
 
 	if (pdev->dev.platform_data == NULL) {
-		dev_err(&pdev->dev, "no platform data supplied");
+		dev_err(&pdev->dev, "no platform data supplied\n");
 		goto err_free_data;
 	}
 	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)
+		status |= SHT15_STATUS_NO_OTP_RELOAD;
+	if (data->pdata->low_resolution)
+		status |= SHT15_STATUS_LOW_RESOLUTION;
 
-/* If a regulator is available, query what the supply voltage actually is!*/
+	/*
+	 * If a regulator is available,
+	 * query what the supply voltage actually is!
+	 */
 	data->reg = regulator_get(data->dev, "vcc");
 	if (!IS_ERR(data->reg)) {
 		int voltage;
@@ -549,28 +926,34 @@
 			data->supply_uV = voltage;
 
 		regulator_enable(data->reg);
-		/* setup a notifier block to update this if another device
-		 *  causes the voltage to change */
+		/*
+		 * Setup a notifier block to update this if another device
+		 * causes the voltage to change
+		 */
 		data->nb.notifier_call = &sht15_invalidate_voltage;
 		ret = regulator_register_notifier(data->reg, &data->nb);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"regulator notifier request failed\n");
+			regulator_disable(data->reg);
+			regulator_put(data->reg);
+			goto err_free_data;
+		}
 	}
-/* Try requesting the GPIOs */
+
+	/* Try requesting the GPIOs */
 	ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
 	if (ret) {
-		dev_err(&pdev->dev, "gpio request failed");
-		goto err_free_data;
+		dev_err(&pdev->dev, "gpio request failed\n");
+		goto err_release_reg;
 	}
 	gpio_direction_output(data->pdata->gpio_sck, 0);
+
 	ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
 	if (ret) {
-		dev_err(&pdev->dev, "gpio request failed");
+		dev_err(&pdev->dev, "gpio request failed\n");
 		goto err_release_gpio_sck;
 	}
-	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
-	if (ret) {
-		dev_err(&pdev->dev, "sysfs create failed");
-		goto err_release_gpio_data;
-	}
 
 	ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
 			  sht15_interrupt_fired,
@@ -578,30 +961,53 @@
 			  "sht15 data",
 			  data);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to get irq for data line");
+		dev_err(&pdev->dev, "failed to get irq for data line\n");
 		goto err_release_gpio_data;
 	}
 	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
 	sht15_connection_reset(data);
-	sht15_send_cmd(data, 0x1E);
+	ret = sht15_soft_reset(data);
+	if (ret)
+		goto err_release_irq;
+
+	/* write status with platform data options */
+	if (status) {
+		ret = sht15_send_status(data, status);
+		if (ret)
+			goto err_release_irq;
+	}
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
+	if (ret) {
+		dev_err(&pdev->dev, "sysfs create failed\n");
+		goto err_release_irq;
+	}
 
 	data->hwmon_dev = hwmon_device_register(data->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		ret = PTR_ERR(data->hwmon_dev);
-		goto err_release_irq;
+		goto err_release_sysfs_group;
 	}
+
 	return 0;
 
+err_release_sysfs_group:
+	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
 err_release_irq:
 	free_irq(gpio_to_irq(data->pdata->gpio_data), data);
 err_release_gpio_data:
 	gpio_free(data->pdata->gpio_data);
 err_release_gpio_sck:
 	gpio_free(data->pdata->gpio_sck);
+err_release_reg:
+	if (!IS_ERR(data->reg)) {
+		regulator_unregister_notifier(data->reg, &data->nb);
+		regulator_disable(data->reg);
+		regulator_put(data->reg);
+	}
 err_free_data:
 	kfree(data);
 error_ret:
-
 	return ret;
 }
 
@@ -609,9 +1015,15 @@
 {
 	struct sht15_data *data = platform_get_drvdata(pdev);
 
-	/* Make sure any reads from the device are done and
-	 * prevent new ones from beginning */
+	/*
+	 * Make sure any reads from the device are done and
+	 * prevent new ones beginning
+	 */
 	mutex_lock(&data->read_lock);
+	if (sht15_soft_reset(data)) {
+		mutex_unlock(&data->read_lock);
+		return -EFAULT;
+	}
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
 	if (!IS_ERR(data->reg)) {
@@ -625,10 +1037,10 @@
 	gpio_free(data->pdata->gpio_sck);
 	mutex_unlock(&data->read_lock);
 	kfree(data);
+
 	return 0;
 }
 
-
 /*
  * sht_drivers simultaneously refers to __devinit and __devexit function
  * which causes spurious section mismatch warning. So use __refdata to
@@ -673,7 +1085,6 @@
 	},
 };
 
-
 static int __init sht15_init(void)
 {
 	int ret;
diff --git a/drivers/hwmon/ucd9000.c b/drivers/hwmon/ucd9000.c
new file mode 100644
index 0000000..ace1c73
--- /dev/null
+++ b/drivers/hwmon/ucd9000.c
@@ -0,0 +1,278 @@
+/*
+ * Hardware monitoring driver for UCD90xxx Sequencer and System Health
+ * Controller series
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 };
+
+#define UCD9000_MONITOR_CONFIG		0xd5
+#define UCD9000_NUM_PAGES		0xd6
+#define UCD9000_FAN_CONFIG_INDEX	0xe7
+#define UCD9000_FAN_CONFIG		0xe8
+#define UCD9000_DEVICE_ID		0xfd
+
+#define UCD9000_MON_TYPE(x)	(((x) >> 5) & 0x07)
+#define UCD9000_MON_PAGE(x)	((x) & 0x0f)
+
+#define UCD9000_MON_VOLTAGE	1
+#define UCD9000_MON_TEMPERATURE	2
+#define UCD9000_MON_CURRENT	3
+#define UCD9000_MON_VOLTAGE_HW	4
+
+#define UCD9000_NUM_FAN		4
+
+struct ucd9000_data {
+	u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
+	struct pmbus_driver_info info;
+};
+#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
+
+static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
+{
+	int fan_config = 0;
+	struct ucd9000_data *data
+	  = to_ucd9000_data(pmbus_get_driver_info(client));
+
+	if (data->fan_data[fan][3] & 1)
+		fan_config |= PB_FAN_2_INSTALLED;   /* Use lower bit position */
+
+	/* Pulses/revolution */
+	fan_config |= (data->fan_data[fan][3] & 0x06) >> 1;
+
+	return fan_config;
+}
+
+static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	int ret = 0;
+	int fan_config;
+
+	switch (reg) {
+	case PMBUS_FAN_CONFIG_12:
+		if (page)
+			return -EINVAL;
+
+		ret = ucd9000_get_fan_config(client, 0);
+		if (ret < 0)
+			return ret;
+		fan_config = ret << 4;
+		ret = ucd9000_get_fan_config(client, 1);
+		if (ret < 0)
+			return ret;
+		fan_config |= ret;
+		ret = fan_config;
+		break;
+	case PMBUS_FAN_CONFIG_34:
+		if (page)
+			return -EINVAL;
+
+		ret = ucd9000_get_fan_config(client, 2);
+		if (ret < 0)
+			return ret;
+		fan_config = ret << 4;
+		ret = ucd9000_get_fan_config(client, 3);
+		if (ret < 0)
+			return ret;
+		fan_config |= ret;
+		ret = fan_config;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static const struct i2c_device_id ucd9000_id[] = {
+	{"ucd9000", ucd9000},
+	{"ucd90120", ucd90120},
+	{"ucd90124", ucd90124},
+	{"ucd9090", ucd9090},
+	{"ucd90910", ucd90910},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9000_id);
+
+static int ucd9000_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+	struct ucd9000_data *data;
+	struct pmbus_driver_info *info;
+	const struct i2c_device_id *mid;
+	int i, ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_BLOCK_DATA))
+		return -ENODEV;
+
+	ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID,
+					block_buffer);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read device ID\n");
+		return ret;
+	}
+	block_buffer[ret] = '\0';
+	dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+	mid = NULL;
+	for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
+		mid = &ucd9000_id[i];
+		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+			break;
+	}
+	if (!mid || !strlen(mid->name)) {
+		dev_err(&client->dev, "Unsupported device\n");
+		return -ENODEV;
+	}
+
+	if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data)
+		dev_notice(&client->dev,
+			   "Device mismatch: Configured %s, detected %s\n",
+			   id->name, mid->name);
+
+	data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	info = &data->info;
+
+	ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"Failed to read number of active pages\n");
+		goto out;
+	}
+	info->pages = ret;
+	if (!info->pages) {
+		dev_err(&client->dev, "No pages configured\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* The internal temperature sensor is always active */
+	info->func[0] = PMBUS_HAVE_TEMP;
+
+	/* Everything else is configurable */
+	ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG,
+					block_buffer);
+	if (ret <= 0) {
+		dev_err(&client->dev, "Failed to read configuration data\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	for (i = 0; i < ret; i++) {
+		int page = UCD9000_MON_PAGE(block_buffer[i]);
+
+		if (page >= info->pages)
+			continue;
+
+		switch (UCD9000_MON_TYPE(block_buffer[i])) {
+		case UCD9000_MON_VOLTAGE:
+		case UCD9000_MON_VOLTAGE_HW:
+			info->func[page] |= PMBUS_HAVE_VOUT
+			  | PMBUS_HAVE_STATUS_VOUT;
+			break;
+		case UCD9000_MON_TEMPERATURE:
+			info->func[page] |= PMBUS_HAVE_TEMP2
+			  | PMBUS_HAVE_STATUS_TEMP;
+			break;
+		case UCD9000_MON_CURRENT:
+			info->func[page] |= PMBUS_HAVE_IOUT
+			  | PMBUS_HAVE_STATUS_IOUT;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Fan configuration */
+	if (mid->driver_data == ucd90124) {
+		for (i = 0; i < UCD9000_NUM_FAN; i++) {
+			i2c_smbus_write_byte_data(client,
+						  UCD9000_FAN_CONFIG_INDEX, i);
+			ret = i2c_smbus_read_block_data(client,
+							UCD9000_FAN_CONFIG,
+							data->fan_data[i]);
+			if (ret < 0)
+				goto out;
+		}
+		i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0);
+
+		info->read_byte_data = ucd9000_read_byte_data;
+		info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
+		  | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
+	}
+
+	ret = pmbus_do_probe(client, mid, info);
+	if (ret < 0)
+		goto out;
+	return 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ucd9000_remove(struct i2c_client *client)
+{
+	int ret;
+	struct ucd9000_data *data;
+
+	data = to_ucd9000_data(pmbus_get_driver_info(client));
+	ret = pmbus_do_remove(client);
+	kfree(data);
+	return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9000_driver = {
+	.driver = {
+		.name = "ucd9000",
+	},
+	.probe = ucd9000_probe,
+	.remove = ucd9000_remove,
+	.id_table = ucd9000_id,
+};
+
+static int __init ucd9000_init(void)
+{
+	return i2c_add_driver(&ucd9000_driver);
+}
+
+static void __exit ucd9000_exit(void)
+{
+	i2c_del_driver(&ucd9000_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
+MODULE_LICENSE("GPL");
+module_init(ucd9000_init);
+module_exit(ucd9000_exit);
diff --git a/drivers/hwmon/ucd9200.c b/drivers/hwmon/ucd9200.c
new file mode 100644
index 0000000..ffcc1cf
--- /dev/null
+++ b/drivers/hwmon/ucd9200.c
@@ -0,0 +1,210 @@
+/*
+ * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+#define UCD9200_PHASE_INFO	0xd2
+#define UCD9200_DEVICE_ID	0xfd
+
+enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246,
+	     ucd9248 };
+
+static const struct i2c_device_id ucd9200_id[] = {
+	{"ucd9200", ucd9200},
+	{"ucd9220", ucd9220},
+	{"ucd9222", ucd9222},
+	{"ucd9224", ucd9224},
+	{"ucd9240", ucd9240},
+	{"ucd9244", ucd9244},
+	{"ucd9246", ucd9246},
+	{"ucd9248", ucd9248},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9200_id);
+
+static int ucd9200_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+	struct pmbus_driver_info *info;
+	const struct i2c_device_id *mid;
+	int i, j, ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_BLOCK_DATA))
+		return -ENODEV;
+
+	ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID,
+					block_buffer);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read device ID\n");
+		return ret;
+	}
+	block_buffer[ret] = '\0';
+	dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+	mid = NULL;
+	for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
+		mid = &ucd9200_id[i];
+		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+			break;
+	}
+	if (!mid || !strlen(mid->name)) {
+		dev_err(&client->dev, "Unsupported device\n");
+		return -ENODEV;
+	}
+	if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data)
+		dev_notice(&client->dev,
+			   "Device mismatch: Configured %s, detected %s\n",
+			   id->name, mid->name);
+
+	info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO,
+					block_buffer);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read phase information\n");
+		goto out;
+	}
+
+	/*
+	 * Calculate number of configured pages (rails) from PHASE_INFO
+	 * register.
+	 * Rails have to be sequential, so we can abort after finding
+	 * the first unconfigured rail.
+	 */
+	info->pages = 0;
+	for (i = 0; i < ret; i++) {
+		if (!block_buffer[i])
+			break;
+		info->pages++;
+	}
+	if (!info->pages) {
+		dev_err(&client->dev, "No rails configured\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	dev_info(&client->dev, "%d rails configured\n", info->pages);
+
+	/*
+	 * Set PHASE registers on all pages to 0xff to ensure that phase
+	 * specific commands will apply to all phases of a given page (rail).
+	 * This only affects the READ_IOUT and READ_TEMPERATURE2 registers.
+	 * READ_IOUT will return the sum of currents of all phases of a rail,
+	 * and READ_TEMPERATURE2 will return the maximum temperature detected
+	 * for the the phases of the rail.
+	 */
+	for (i = 0; i < info->pages; i++) {
+		/*
+		 * Setting PAGE & PHASE fails once in a while for no obvious
+		 * reason, so we need to retry a couple of times.
+		 */
+		for (j = 0; j < 3; j++) {
+			ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+			if (ret < 0)
+				continue;
+			ret = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
+							0xff);
+			if (ret < 0)
+				continue;
+			break;
+		}
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"Failed to initialize PHASE registers\n");
+			goto out;
+		}
+	}
+	if (info->pages > 1)
+		i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+
+	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+			PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+			PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+			PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP |
+			PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+	for (i = 1; i < info->pages; i++)
+		info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+			PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+			PMBUS_HAVE_POUT |
+			PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+	/* ucd9240 supports a single fan */
+	if (mid->driver_data == ucd9240)
+		info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12;
+
+	ret = pmbus_do_probe(client, mid, info);
+	if (ret < 0)
+		goto out;
+	return 0;
+out:
+	kfree(info);
+	return ret;
+}
+
+static int ucd9200_remove(struct i2c_client *client)
+{
+	int ret;
+	const struct pmbus_driver_info *info;
+
+	info = pmbus_get_driver_info(client);
+	ret = pmbus_do_remove(client);
+	kfree(info);
+	return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9200_driver = {
+	.driver = {
+		.name = "ucd9200",
+	},
+	.probe = ucd9200_probe,
+	.remove = ucd9200_remove,
+	.id_table = ucd9200_id,
+};
+
+static int __init ucd9200_init(void)
+{
+	return i2c_add_driver(&ucd9200_driver);
+}
+
+static void __exit ucd9200_exit(void)
+{
+	i2c_del_driver(&ucd9200_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
+MODULE_LICENSE("GPL");
+module_init(ucd9200_init);
+module_exit(ucd9200_exit);
diff --git a/include/linux/sht15.h b/include/linux/sht15.h
index 046bce0..f85c7c5 100644
--- a/include/linux/sht15.h
+++ b/include/linux/sht15.h
@@ -8,17 +8,27 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/sht15 file.
  */
 
 /**
  * struct sht15_platform_data - sht15 connectivity info
- * @gpio_data:	no. of gpio to which bidirectional data line is connected
- * @gpio_sck:	no. of gpio to which the data clock is connected.
- * @supply_mv:	supply voltage in mv. Overridden by regulator if available.
- **/
+ * @gpio_data:		no. of gpio to which bidirectional data line is
+ *			connected.
+ * @gpio_sck:		no. of gpio to which the data clock is connected.
+ * @supply_mv:		supply voltage in mv. Overridden by regulator if
+ *			available.
+ * @checksum:		flag to indicate the checksum should be validated.
+ * @no_otp_reload:	flag to indicate no reload from OTP.
+ * @low_resolution:	flag to indicate the temp/humidity resolution to use.
+ */
 struct sht15_platform_data {
 	int gpio_data;
 	int gpio_sck;
 	int supply_mv;
+	bool checksum;
+	bool no_otp_reload;
+	bool low_resolution;
 };