File-copy from v4.4.100

This is the result of 'cp' from a linux-stable tree with the 'v4.4.100'
tag checked out (commit 26d6298789e695c9f627ce49a7bbd2286405798a) on
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git

Please refer to that tree for all history prior to this point.

Change-Id: I8a9ee2aea93cd29c52c847d0ce33091a73ae6afe
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
new file mode 100644
index 0000000..80a73bf
--- /dev/null
+++ b/drivers/hwmon/Kconfig
@@ -0,0 +1,1788 @@
+#
+# Hardware monitoring chip drivers configuration
+#
+
+menuconfig HWMON
+	tristate "Hardware Monitoring support"
+	depends on HAS_IOMEM
+	default y
+	help
+	  Hardware monitoring devices let you monitor the hardware health
+	  of a system. Most modern motherboards include such a device. It
+	  can include temperature sensors, voltage sensors, fan speed
+	  sensors and various additional features such as the ability to
+	  control the speed of the fans.  If you want this support you
+	  should say Y here and also to the specific driver(s) for your
+	  sensors chip(s) below.
+
+	  To find out which specific driver(s) you need, use the
+	  sensors-detect script from the lm_sensors package.  Read
+	  <file:Documentation/hwmon/userspace-tools> for details.
+
+	  This support can also be built as a module.  If so, the module
+	  will be called hwmon.
+
+if HWMON
+
+config HWMON_VID
+	tristate
+	default n
+
+config HWMON_DEBUG_CHIP
+	bool "Hardware Monitoring Chip debugging messages"
+	default n
+	help
+	  Say Y here if you want the I2C chip drivers to produce a bunch of
+	  debug messages to the system log.  Select this if you are having
+	  a problem with I2C support and want to see more of what is going
+	  on.
+
+comment "Native drivers"
+
+config SENSORS_AB8500
+	tristate "AB8500 thermal monitoring"
+	depends on AB8500_GPADC && AB8500_BM
+	default n
+	help
+	  If you say yes here you get support for the thermal sensor part
+	  of the AB8500 chip. The driver includes thermal management for
+	  AB8500 die and two GPADC channels. The GPADC channel are preferably
+	  used to access sensors outside the AB8500 chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called abx500-temp.
+
+config SENSORS_ABITUGURU
+	tristate "Abit uGuru (rev 1 & 2)"
+	depends on X86 && DMI
+	help
+	  If you say yes here you get support for the sensor part of the first
+	  and second revision of the Abit uGuru chip. The voltage and frequency
+	  control parts of the Abit uGuru are not supported. The Abit uGuru
+	  chip can be found on Abit uGuru featuring motherboards (most modern
+	  Abit motherboards from before end 2005). For more info and a list
+	  of which motherboards have which revision see
+	  Documentation/hwmon/abituguru
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called abituguru.
+
+config SENSORS_ABITUGURU3
+	tristate "Abit uGuru (rev 3)"
+	depends on X86 && DMI
+	help
+	  If you say yes here you get support for the sensor part of the
+	  third revision of the Abit uGuru chip. Only reading the sensors
+	  and their settings is supported. The third revision of the Abit
+	  uGuru chip can be found on recent Abit motherboards (since end
+	  2005). For more info and a list of which motherboards have which
+	  revision see Documentation/hwmon/abituguru3
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called abituguru3.
+
+config SENSORS_AD7314
+	tristate "Analog Devices AD7314 and compatibles"
+	depends on SPI
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7314, ADT7301 and ADT7302 temperature sensors.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7314.
+
+config SENSORS_AD7414
+	tristate "Analog Devices AD7414"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7414 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7414.
+
+config SENSORS_AD7418
+	tristate "Analog Devices AD7416, AD7417 and AD7418"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7416, AD7417 and AD7418 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7418.
+
+config SENSORS_ADM1021
+	tristate "Analog Devices ADM1021 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for Analog Devices ADM1021
+	  and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
+	  Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1021.
+
+config SENSORS_ADM1025
+	tristate "Analog Devices ADM1025 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for Analog Devices ADM1025
+	  and Philips NE1619 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1025.
+
+config SENSORS_ADM1026
+	tristate "Analog Devices ADM1026 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for Analog Devices ADM1026
+	  sensor chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1026.
+
+config SENSORS_ADM1029
+	tristate "Analog Devices ADM1029"
+	depends on I2C
+	help
+	  If you say yes here you get support for Analog Devices ADM1029
+	  sensor chip.
+	  Very rare chip, please let us know you use it.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1029.
+
+config SENSORS_ADM1031
+	tristate "Analog Devices ADM1031 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for Analog Devices ADM1031
+	  and ADM1030 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1031.
+
+config SENSORS_ADM9240
+	tristate "Analog Devices ADM9240 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for Analog Devices ADM9240,
+	  Dallas DS1780, National Semiconductor LM81 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm9240.
+
+config SENSORS_ADT7X10
+	tristate
+	help
+	  This module contains common code shared by the ADT7310/ADT7320 and
+	  ADT7410/ADT7420 temperature monitoring chip drivers.
+
+	  If build as a module, the module will be called adt7x10.
+
+config SENSORS_ADT7310
+	tristate "Analog Devices ADT7310/ADT7320"
+	depends on SPI_MASTER
+	select SENSORS_ADT7X10
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7310 and ADT7320 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7310.
+
+config SENSORS_ADT7410
+	tristate "Analog Devices ADT7410/ADT7420"
+	depends on I2C
+	select SENSORS_ADT7X10
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7410 and ADT7420 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7410.
+
+config SENSORS_ADT7411
+	tristate "Analog Devices ADT7411"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7411 voltage and temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7411.
+
+config SENSORS_ADT7462
+	tristate "Analog Devices ADT7462"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7462 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7462.
+
+config SENSORS_ADT7470
+	tristate "Analog Devices ADT7470"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7470 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7470.
+
+config SENSORS_ADT7475
+	tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7473, ADT7475, ADT7476 and ADT7490 hardware monitoring
+	  chips.
+
+	  This driver can also be build as a module.  If so, the module
+	  will be called adt7475.
+
+config SENSORS_ASC7621
+	tristate "Andigilog aSC7621"
+	depends on I2C
+	help
+	  If you say yes here you get support for the aSC7621
+	  family of SMBus sensors chip found on most Intel X38, X48, X58,
+	  945, 965 and 975 desktop boards.  Currently supported chips:
+	  aSC7621
+	  aSC7621a
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called asc7621.
+
+config SENSORS_K8TEMP
+	tristate "AMD Athlon64/FX or Opteron temperature sensor"
+	depends on X86 && PCI
+	help
+	  If you say yes here you get support for the temperature
+	  sensor(s) inside your CPU. Supported is whole AMD K8
+	  microarchitecture. Please note that you will need at least
+	  lm-sensors 2.10.1 for proper userspace support.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called k8temp.
+
+config SENSORS_K10TEMP
+	tristate "AMD Family 10h+ temperature sensor"
+	depends on X86 && PCI
+	help
+	  If you say yes here you get support for the temperature
+	  sensor(s) inside your CPU. Supported are later revisions of
+	  the AMD Family 10h and all revisions of the AMD Family 11h,
+	  12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri/Carrizo)
+	  and 16h (Kabini/Mullins) microarchitectures.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called k10temp.
+
+config SENSORS_FAM15H_POWER
+	tristate "AMD Family 15h processor power"
+	depends on X86 && PCI
+	help
+	  If you say yes here you get support for processor power
+	  information of your AMD family 15h CPU.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called fam15h_power.
+
+config SENSORS_APPLESMC
+	tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+	depends on INPUT && X86
+	select NEW_LEDS
+	select LEDS_CLASS
+	select INPUT_POLLDEV
+	default n
+	help
+	  This driver provides support for the Apple System Management
+	  Controller, which provides an accelerometer (Apple Sudden Motion
+	  Sensor), light sensors, temperature sensors, keyboard backlight
+	  control and fan control.
+
+	  Only Intel-based Apple's computers are supported (MacBook Pro,
+	  MacBook, MacMini).
+
+	  Data from the different sensors, keyboard backlight control and fan
+	  control are accessible via sysfs.
+
+	  This driver also provides an absolute input class device, allowing
+	  the laptop to act as a pinball machine-esque joystick.
+
+	  Say Y here if you have an applicable laptop and want to experience
+	  the awesome power of applesmc.
+
+config SENSORS_ARM_SCPI
+	tristate "ARM SCPI Sensors"
+	depends on ARM_SCPI_PROTOCOL
+	depends on THERMAL || !THERMAL_OF
+	help
+	  This driver provides support for temperature, voltage, current
+	  and power sensors available on ARM Ltd's SCP based platforms. The
+	  actual number and type of sensors exported depend on the platform.
+
+config SENSORS_ASB100
+	tristate "Asus ASB100 Bach"
+	depends on X86 && I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the ASB100 Bach sensor
+	  chip found on some Asus mainboards.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called asb100.
+
+config SENSORS_ATXP1
+	tristate "Attansic ATXP1 VID controller"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Attansic ATXP1 VID
+	  controller.
+
+	  If your board have such a chip, you are able to control your CPU
+	  core and other voltages.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called atxp1.
+
+config SENSORS_DS620
+	tristate "Dallas Semiconductor DS620"
+	depends on I2C
+	help
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS620 sensor chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds620.
+
+config SENSORS_DS1621
+	tristate "Dallas Semiconductor DS1621 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for Dallas Semiconductor/Maxim
+	  Integrated DS1621 sensor chips and compatible models including:
+
+	  - Dallas Semiconductor DS1625
+	  - Maxim Integrated DS1631
+	  - Maxim Integrated DS1721
+	  - Maxim Integrated DS1731
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds1621.
+
+config SENSORS_DELL_SMM
+	tristate "Dell laptop SMM BIOS hwmon driver"
+	depends on X86
+	help
+	  This hwmon driver adds support for reporting temperature of different
+	  sensors and controls the fans on Dell laptops via System Management
+	  Mode provided by Dell BIOS.
+
+	  When option I8K is also enabled this driver provides legacy /proc/i8k
+	  userspace interface for i8kutils package.
+
+config SENSORS_DA9052_ADC
+	tristate "Dialog DA9052/DA9053 ADC"
+	depends on PMIC_DA9052
+	help
+	  Say y here to support the ADC found on Dialog Semiconductor
+	  DA9052-BC and DA9053-AA/Bx PMICs.
+
+	  This driver can also be built as module. If so, the module
+	  will be called da9052-hwmon.
+
+config SENSORS_DA9055
+	tristate "Dialog Semiconductor DA9055 ADC"
+	depends on MFD_DA9055
+	help
+	  If you say yes here you get support for ADC on the Dialog
+	  Semiconductor DA9055 PMIC.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called da9055-hwmon.
+
+config SENSORS_I5K_AMB
+	tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
+	depends on PCI
+	help
+	  If you say yes here you get support for FB-DIMM AMB temperature
+	  monitoring chips on systems with the Intel 5000 series chipset.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i5k_amb.
+
+config SENSORS_F71805F
+	tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
+	depends on !PPC
+	help
+	  If you say yes here you get support for hardware monitoring
+	  features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
+	  Super-I/O chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called f71805f.
+
+config SENSORS_F71882FG
+	tristate "Fintek F71882FG and compatibles"
+	depends on !PPC
+	help
+	  If you say yes here you get support for hardware monitoring
+	  features of many Fintek Super-I/O (LPC) chips. The currently
+	  supported chips are:
+	    F71808E/A
+	    F71858FG
+	    F71862FG
+	    F71863FG
+	    F71869F/E/A
+	    F71882FG
+	    F71883FG
+	    F71889FG/ED/A
+	    F8000
+	    F81801U
+	    F81865F
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called f71882fg.
+
+config SENSORS_F75375S
+	tristate "Fintek F75375S/SP, F75373 and F75387"
+	depends on I2C
+	help
+	  If you say yes here you get support for hardware monitoring
+	  features of the Fintek F75375S/SP, F75373 and F75387
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called f75375s.
+
+config SENSORS_MC13783_ADC
+        tristate "Freescale MC13783/MC13892 ADC"
+        depends on MFD_MC13XXX
+        help
+          Support for the A/D converter on MC13783 and MC13892 PMIC.
+
+config SENSORS_FSCHMD
+	tristate "Fujitsu Siemens Computers sensor chips"
+	depends on X86 && I2C
+	help
+	  If you say yes here you get support for the following Fujitsu
+	  Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
+	  Heimdall, Heracles, Hades and Syleus including support for the
+	  integrated watchdog.
+
+	  This is a merged driver for FSC sensor chips replacing the fscpos,
+	  fscscy and fscher drivers and adding support for several other FSC
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called fschmd.
+
+config SENSORS_GL518SM
+	tristate "Genesys Logic GL518SM"
+	depends on I2C
+	help
+	  If you say yes here you get support for Genesys Logic GL518SM
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gl518sm.
+
+config SENSORS_GL520SM
+	tristate "Genesys Logic GL520SM"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for Genesys Logic GL520SM
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gl520sm.
+
+config SENSORS_G760A
+	tristate "GMT G760A"
+	depends on I2C
+	help
+	  If you say yes here you get support for Global Mixed-mode
+	  Technology Inc G760A fan speed PWM controller chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called g760a.
+
+config SENSORS_G762
+	tristate "GMT G762 and G763"
+	depends on I2C
+	help
+	  If you say yes here you get support for Global Mixed-mode
+	  Technology Inc G762 and G763 fan speed PWM controller chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called g762.
+
+config SENSORS_GPIO_FAN
+	tristate "GPIO fan"
+	depends on GPIOLIB || COMPILE_TEST
+	depends on THERMAL || THERMAL=n
+	help
+	  If you say yes here you get support for fans connected to GPIO lines.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-fan.
+
+config SENSORS_HIH6130
+	tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
+	depends on I2C
+	help
+	  If you say yes here you get support for Honeywell Humidicon
+	  HIH-6130 and HIH-6131 Humidicon humidity sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called hih6130.
+
+config SENSORS_IBMAEM
+	tristate "IBM Active Energy Manager temperature/power sensors and control"
+	select IPMI_SI
+	depends on IPMI_HANDLER
+	help
+	  If you say yes here you get support for the temperature and
+	  power sensors and capping hardware in various IBM System X
+	  servers that support Active Energy Manager.  This includes
+	  the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2,
+	  and certain HC10/HS2x/LS2x/QS2x blades.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ibmaem.
+
+config SENSORS_IBMPEX
+	tristate "IBM PowerExecutive temperature/power sensors"
+	select IPMI_SI
+	depends on IPMI_HANDLER
+	help
+	  If you say yes here you get support for the temperature and
+	  power sensors in various IBM System X servers that support
+	  PowerExecutive.  So far this includes the x3350, x3550, x3650,
+	  x3655, and x3755; the x3800, x3850, and x3950 models that have
+	  PCI Express; and some of the HS2x, LS2x, and QS2x blades.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ibmpex.
+
+config SENSORS_IBMPOWERNV
+	tristate "IBM POWERNV platform sensors"
+	depends on PPC_POWERNV
+	default y
+	help
+	  If you say yes here you get support for the temperature/fan/power
+	  sensors on your PowerNV platform.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ibmpowernv.
+
+config SENSORS_IIO_HWMON
+	tristate "Hwmon driver that uses channels specified via iio maps"
+	depends on IIO
+	help
+	  This is a platform driver that in combination with a suitable
+	  map allows IIO devices to provide basic hwmon functionality
+	  for those channels specified in the map.  This map can be provided
+	  either via platform data or the device tree bindings.
+
+config SENSORS_I5500
+	tristate "Intel 5500/5520/X58 temperature sensor"
+	depends on X86 && PCI
+	help
+	  If you say yes here you get support for the temperature
+	  sensor inside the Intel 5500, 5520 and X58 chipsets.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i5500_temp.
+
+config SENSORS_CORETEMP
+	tristate "Intel Core/Core2/Atom temperature sensor"
+	depends on X86
+	help
+	  If you say yes here you get support for the temperature
+	  sensor inside your CPU. Most of the family 6 CPUs
+	  are supported. Check Documentation/hwmon/coretemp for details.
+
+config SENSORS_IT87
+	tristate "ITE IT87xx and compatibles"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F,
+	  IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E,
+	  IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E,
+	  IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called it87.
+
+config SENSORS_JZ4740
+	tristate "Ingenic JZ4740 SoC ADC driver"
+	depends on MACH_JZ4740 && MFD_JZ4740_ADC
+	help
+	  If you say yes here you get support for reading adc values from the ADCIN
+	  pin on Ingenic JZ4740 SoC based boards.
+
+	  This driver can also be build as a module. If so, the module will be
+	  called jz4740-hwmon.
+
+config SENSORS_JC42
+	tristate "JEDEC JC42.4 compliant memory module temperature sensors"
+	depends on I2C
+	help
+	  If you say yes here, you get support for JEDEC JC42.4 compliant
+	  temperature sensors, which are used on many DDR3 memory modules for
+	  mobile devices and servers.  Support will include, but not be limited
+	  to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
+	  MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E),
+	  STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called jc42.
+
+config SENSORS_POWR1220
+	tristate "Lattice POWR1220 Power Monitoring"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get access to the hardware monitoring
+	  functions of the Lattice POWR1220 isp Power Supply Monitoring,
+	  Sequencing and Margining Controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called powr1220.
+
+config SENSORS_LINEAGE
+	tristate "Lineage Compact Power Line Power Entry Module"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Lineage Compact Power Line
+	  series of DC/DC and AC/DC converters such as CP1800, CP2000AC,
+	  CP2000DC, CP2725, and others.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lineage-pem.
+
+config SENSORS_LTC2945
+	tristate "Linear Technology LTC2945"
+	depends on I2C
+	select REGMAP_I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC2945
+	  I2C System Monitor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc2945.
+
+config SENSORS_LTC4151
+	tristate "Linear Technology LTC4151"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4151
+	  High Voltage I2C Current and Voltage Monitor interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4151.
+
+config SENSORS_LTC4215
+	tristate "Linear Technology LTC4215"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4215
+	  Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4215.
+
+config SENSORS_LTC4222
+	tristate "Linear Technology LTC4222"
+	depends on I2C
+	select REGMAP_I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4222
+	  Dual Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4222.
+
+config SENSORS_LTC4245
+	tristate "Linear Technology LTC4245"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4245
+	  Multiple Supply Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4245.
+
+config SENSORS_LTC4260
+	tristate "Linear Technology LTC4260"
+	depends on I2C
+	select REGMAP_I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4260
+	  Positive Voltage Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4260.
+
+config SENSORS_LTC4261
+	tristate "Linear Technology LTC4261"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4261
+	  Negative Voltage Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4261.
+
+config SENSORS_MAX1111
+	tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
+	depends on SPI_MASTER
+	help
+	  Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
+	  ADC chips.
+
+	  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
+	help
+	  If you say yes here you get support for MAX1619 sensor chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max1619.
+
+config SENSORS_MAX1668
+	tristate "Maxim MAX1668 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for MAX1668, MAX1989 and
+	  MAX1805 chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max1668.
+
+config SENSORS_MAX197
+	tristate "Maxim MAX197 and compatibles"
+	help
+	  Support for the Maxim MAX197 A/D converter.
+	  Support will include, but not be limited to, MAX197, and MAX199.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called max197.
+
+config SENSORS_MAX6639
+	tristate "Maxim MAX6639 sensor chip"
+	depends on I2C
+	help
+	  If you say yes here you get support for the MAX6639
+	  sensor chips.
+
+	  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
+	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
+	help
+	  If you say yes here you get support for the MAX6650 / MAX6651
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max6650.
+
+config SENSORS_MAX6697
+	tristate "Maxim MAX6697 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+	  MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+	  temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max6697.
+
+config SENSORS_MAX31790
+	tristate "Maxim MAX31790 sensor chip"
+	depends on I2C
+	help
+	  If you say yes here you get support for 6-Channel PWM-Output
+	  Fan RPM Controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max31790.
+
+config SENSORS_HTU21
+	tristate "Measurement Specialties HTU21D humidity/temperature sensors"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  HTU21D humidity and temperature sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called htu21.
+
+config SENSORS_MCP3021
+	tristate "Microchip MCP3021 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for MCP3021 and MCP3221.
+	  The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
+	  with 12-bit resolution.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called mcp3021.
+
+config SENSORS_MENF21BMC_HWMON
+	tristate "MEN 14F021P00 BMC Hardware Monitoring"
+	depends on MFD_MENF21BMC
+	help
+	  Say Y here to include support for the MEN 14F021P00 BMC
+	  hardware monitoring.
+
+	  This driver can also be built as a module. If so the module
+	  will be called menf21bmc_hwmon.
+
+config SENSORS_ADCXX
+	tristate "National Semiconductor ADCxxxSxxx"
+	depends on SPI_MASTER
+	help
+	  If you say yes here you get support for the National Semiconductor
+	  ADC<bb><c>S<sss> chip family, where
+	  * bb  is the resolution in number of bits (8, 10, 12)
+	  * c   is the number of channels (1, 2, 4, 8)
+	  * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
+	    kSPS and 101 for 1 MSPS)
+
+	  Examples : ADC081S101, ADC124S501, ...
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adcxx.
+
+config SENSORS_LM63
+	tristate "National Semiconductor LM63 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for the National
+	  Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
+	  sensors with integrated fan control.  Such chips are found
+	  on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
+	  others.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm63.
+
+config SENSORS_LM70
+	tristate "National Semiconductor LM70 and compatibles"
+	depends on SPI_MASTER
+	help
+	  If you say yes here you get support for the National Semiconductor
+	  LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
+	  ture sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm70.
+
+config SENSORS_LM73
+	tristate "National Semiconductor LM73"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor LM73
+	  sensor chips.
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm73.
+
+config SENSORS_LM75
+	tristate "National Semiconductor LM75 and compatibles"
+	depends on I2C
+	depends on THERMAL || !THERMAL_OF
+	help
+	  If you say yes here you get support for one common type of
+	  temperature sensor chip, with models including:
+
+		- Analog Devices ADT75
+		- Dallas Semiconductor DS75, DS1775 and DS7505
+		- Global Mixed-mode Technology (GMT) G751
+		- Maxim MAX6625 and MAX6626
+		- Microchip MCP980x
+		- National Semiconductor LM75, LM75A
+		- NXP's LM75A
+		- ST Microelectronics STDS75
+		- TelCom (now Microchip) TCN75
+		- Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75,
+		  TMP175, TMP275
+
+	  This driver supports driver model based binding through board
+	  specific I2C device tables.
+
+	  It also supports the "legacy" style of driver binding.  To use
+	  that with some chips which don't replicate LM75 quirks exactly,
+	  you may need the "force" module parameter.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm75.
+
+config SENSORS_LM77
+	tristate "National Semiconductor LM77"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor LM77
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm77.
+
+config SENSORS_LM78
+	tristate "National Semiconductor LM78 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for National Semiconductor LM78,
+	  LM78-J and LM79.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm78.
+
+config SENSORS_LM80
+	tristate "National Semiconductor LM80 and LM96080"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor
+	  LM80 and LM96080 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm80.
+
+config SENSORS_LM83
+	tristate "National Semiconductor LM83 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor
+	  LM82 and LM83 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm83.
+
+config SENSORS_LM85
+	tristate "National Semiconductor LM85 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for National Semiconductor LM85
+	  sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
+	  EMC6D101, EMC6D102, and EMC6D103.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm85.
+
+config SENSORS_LM87
+	tristate "National Semiconductor LM87 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for National Semiconductor LM87
+	  and Analog Devices ADM1024 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm87.
+
+config SENSORS_LM90
+	tristate "National Semiconductor LM90 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor LM90,
+	  LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
+	  Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
+	  MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
+	  Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm90.
+
+config SENSORS_LM92
+	tristate "National Semiconductor LM92 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for National Semiconductor LM92
+	  and Maxim MAX6635 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm92.
+
+config SENSORS_LM93
+	tristate "National Semiconductor LM93 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for National Semiconductor LM93,
+	  LM94, and compatible sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm93.
+
+config SENSORS_LM95234
+	tristate "National Semiconductor LM95234 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for the LM95233 and LM95234
+	  temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm95234.
+
+config SENSORS_LM95241
+	tristate "National Semiconductor LM95241 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for LM95231 and LM95241 sensor
+	  chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm95241.
+
+config SENSORS_LM95245
+	tristate "National Semiconductor LM95245 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for LM95235 and LM95245
+	  temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm95245.
+
+config SENSORS_PC87360
+	tristate "National Semiconductor PC87360 family"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get access to the hardware monitoring
+	  functions of the National Semiconductor PC8736x Super-I/O chips.
+	  The PC87360, PC87363 and PC87364 only have fan monitoring and
+	  control.  The PC87365 and PC87366 additionally have voltage and
+	  temperature monitoring.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pc87360.
+
+config SENSORS_PC87427
+	tristate "National Semiconductor PC87427"
+	depends on !PPC
+	help
+	  If you say yes here you get access to the hardware monitoring
+	  functions of the National Semiconductor PC87427 Super-I/O chip.
+	  The chip has two distinct logical devices, one for fan speed
+	  monitoring and control, and one for voltage and temperature
+	  monitoring. Fan speed monitoring and control are supported, as
+	  well as temperature monitoring. Voltages aren't supported yet.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pc87427.
+
+config SENSORS_NTC_THERMISTOR
+	tristate "NTC thermistor support from Murata"
+	depends on !OF || IIO=n || IIO
+	depends on THERMAL || !THERMAL_OF
+	help
+	  This driver supports NTC thermistors sensor reading and its
+	  interpretation. The driver can also monitor the temperature and
+	  send notifications about the temperature.
+
+	  Currently, this driver supports
+	  NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333,
+	  and NCP03WF104 from Murata and B57330V2103 from EPCOS.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ntc-thermistor.
+
+config SENSORS_NCT6683
+	tristate "Nuvoton NCT6683D"
+	depends on !PPC
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  functionality of the Nuvoton NCT6683D eSIO chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called nct6683.
+
+config SENSORS_NCT6775
+	tristate "Nuvoton NCT6775F and compatibles"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D,
+	  NCT6791D, NCT6792D, NCT6793D, and compatible Super-I/O chips. This
+	  driver replaces the w83627ehf driver for NCT6775F and NCT6776F.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called nct6775.
+
+config SENSORS_NCT7802
+	tristate "Nuvoton NCT7802Y"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the Nuvoton NCT7802Y
+	  hardware monitoring chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called nct7802.
+
+config SENSORS_NCT7904
+	tristate "Nuvoton NCT7904"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Nuvoton NCT7904
+	  hardware monitoring chip, including manual fan speed control.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called nct7904.
+
+config SENSORS_PCF8591
+	tristate "Philips PCF8591 ADC/DAC"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for Philips PCF8591 4-channel
+	  ADC, 1-channel DAC chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pcf8591.
+
+	  These devices are hard to detect and rarely found on mainstream
+	  hardware.  If unsure, say N.
+
+source drivers/hwmon/pmbus/Kconfig
+
+config SENSORS_PWM_FAN
+	tristate "PWM fan"
+	depends on (PWM && OF) || COMPILE_TEST
+	depends on THERMAL || THERMAL=n
+	help
+	  If you say yes here you get support for fans connected to PWM lines.
+	  The driver uses the generic PWM interface, thus it will work on a
+	  variety of SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pwm-fan.
+
+config SENSORS_SHT15
+	tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
+	depends on GPIOLIB || COMPILE_TEST
+	select BITREVERSE
+	help
+	  If you say yes here you get support for the Sensiron SHT10, SHT11,
+	  SHT15, SHT71, SHT75 humidity and temperature sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sht15.
+
+config SENSORS_SHT21
+	tristate "Sensiron humidity and temperature sensors. SHT21 and compat."
+	depends on I2C
+	help
+	  If you say yes here you get support for the Sensiron SHT21, SHT25
+	  humidity and temperature sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sht21.
+
+config SENSORS_SHTC1
+	tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
+	depends on I2C
+	help
+	  If you say yes here you get support for the Sensiron SHTC1 and SHTW1
+	  humidity and temperature sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called shtc1.
+
+config SENSORS_S3C
+	tristate "Samsung built-in ADC"
+	depends on S3C_ADC
+	help
+	  If you say yes here you get support for the on-board ADCs of
+	  the Samsung S3C24XX, S3C64XX and other series of SoC
+
+	  This driver can also be built as a module. If so, the module
+	  will be called s3c-hwmon.
+
+config SENSORS_S3C_RAW
+	bool "Include raw channel attributes in sysfs"
+	depends on SENSORS_S3C
+	help
+	  Say Y here if you want to include raw copies of all the ADC
+	  channels in sysfs.
+
+config SENSORS_SIS5595
+	tristate "Silicon Integrated Systems Corp. SiS5595"
+	depends on PCI
+	help
+	  If you say yes here you get support for the integrated sensors in
+	  SiS5595 South Bridges.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sis5595.
+
+config SENSORS_DME1737
+	tristate "SMSC DME1737, SCH311x and compatibles"
+	depends on I2C && !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
+	  Asus A8000 Super-I/O chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called dme1737.
+
+config SENSORS_EMC1403
+	tristate "SMSC EMC1403/23 thermal sensor"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the SMSC EMC1403/23
+	  temperature monitoring chip.
+
+	  Threshold values can be configured using sysfs.
+	  Data from the different diodes are accessible via sysfs.
+
+config SENSORS_EMC2103
+	tristate "SMSC EMC2103"
+	depends on I2C
+	help
+	  If you say yes here you get support for the temperature
+	  and fan sensors of the SMSC EMC2103 chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called emc2103.
+
+config SENSORS_EMC6W201
+	tristate "SMSC EMC6W201"
+	depends on I2C
+	help
+	  If you say yes here you get support for the SMSC EMC6W201
+	  hardware monitoring chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called emc6w201.
+
+config SENSORS_SMSC47M1
+	tristate "SMSC LPC47M10x and compatibles"
+	depends on !PPC
+	help
+	  If you say yes here you get support for the integrated fan
+	  monitoring and control capabilities of the SMSC LPC47B27x,
+	  LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x,
+	  LPC47M192, LPC47M292 and LPC47M997 chips.
+
+	  The temperature and voltage sensor features of the LPC47M15x,
+	  LPC47M192, LPC47M292 and LPC47M997 are supported by another
+	  driver, select also "SMSC LPC47M192 and compatibles" below for
+	  those.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called smsc47m1.
+
+config SENSORS_SMSC47M192
+	tristate "SMSC LPC47M192 and compatibles"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the temperature and
+	  voltage sensors of the SMSC LPC47M192, LPC47M15x, LPC47M292
+	  and LPC47M997 chips.
+
+	  The fan monitoring and control capabilities of these chips
+	  are supported by another driver, select
+	  "SMSC LPC47M10x and compatibles" above. You need both drivers
+	  if you want fan control and voltage/temperature sensor support.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called smsc47m192.
+
+config SENSORS_SMSC47B397
+	tristate "SMSC LPC47B397-NC"
+	depends on !PPC
+	help
+	  If you say yes here you get support for the SMSC LPC47B397-NC
+	  sensor chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called smsc47b397.
+
+config SENSORS_SCH56XX_COMMON
+	tristate
+	default n
+
+config SENSORS_SCH5627
+	tristate "SMSC SCH5627"
+	depends on !PPC && WATCHDOG
+	select SENSORS_SCH56XX_COMMON
+	select WATCHDOG_CORE
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  features of the SMSC SCH5627 Super-I/O chip including support for
+	  the integrated watchdog.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sch5627.
+
+config SENSORS_SCH5636
+	tristate "SMSC SCH5636"
+	depends on !PPC && WATCHDOG
+	select SENSORS_SCH56XX_COMMON
+	select WATCHDOG_CORE
+	help
+	  SMSC SCH5636 Super I/O chips include an embedded microcontroller for
+	  hardware monitoring solutions, allowing motherboard manufacturers to
+	  create their own custom hwmon solution based upon the SCH5636.
+
+	  Currently this driver only supports the Fujitsu Theseus SCH5636 based
+	  hwmon solution. Say yes here if you want support for the Fujitsu
+	  Theseus' hardware monitoring features including support for the
+	  integrated watchdog.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sch5636.
+
+config SENSORS_SMM665
+	tristate "Summit Microelectronics SMM665"
+	depends on I2C
+	default n
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  features of the Summit Microelectronics SMM665/SMM665B Six-Channel
+	  Active DC Output Controller / Monitor.
+
+	  Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
+	  Support for those chips is untested.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called smm665.
+
+config SENSORS_ADC128D818
+	tristate "Texas Instruments ADC128D818"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Texas Instruments
+	  ADC128D818 System Monitor with Temperature Sensor chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adc128d818.
+
+config SENSORS_ADS1015
+	tristate "Texas Instruments ADS1015"
+	depends on I2C
+	help
+	  If you say yes here you get support for Texas Instruments
+	  ADS1015/ADS1115 12/16-bit 4-input ADC device.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ads1015.
+
+config SENSORS_ADS7828
+	tristate "Texas Instruments ADS7828 and compatibles"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for Texas Instruments ADS7828 and
+	  ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while
+	  it is 8-bit on ADS7830.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ads7828.
+
+config SENSORS_ADS7871
+	tristate "Texas Instruments ADS7871 A/D converter"
+	depends on SPI
+	help
+	  If you say yes here you get support for TI ADS7871 & ADS7870
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ads7871.
+
+config SENSORS_AMC6821
+	tristate "Texas Instruments AMC6821"
+	depends on I2C 
+	help
+	  If you say yes here you get support for the Texas Instruments
+	  AMC6821 hardware monitoring chips.
+
+	  This driver can also be build as a module.  If so, the module
+	  will be called amc6821.
+
+config SENSORS_INA209
+	tristate "TI / Burr Brown INA209"
+	depends on I2C
+	help
+	  If you say yes here you get support for the TI / Burr Brown INA209
+	  voltage / current / power monitor I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ina209.
+
+config SENSORS_INA2XX
+	tristate "Texas Instruments INA219 and compatibles"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for INA219, INA220, INA226,
+	  INA230, and INA231 power monitor chips.
+
+	  The INA2xx driver is configured for the default configuration of
+	  the part as described in the datasheet.
+	  Default value for Rshunt is 10 mOhms.
+	  This driver can also be built as a module.  If so, the module
+	  will be called ina2xx.
+
+config SENSORS_TC74
+	tristate "Microchip TC74"
+	depends on I2C
+	help
+	  If you say yes here you get support for Microchip TC74 single
+	  input temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tc74.
+
+config SENSORS_THMC50
+	tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
+	depends on I2C
+	help
+	  If you say yes here you get support for Texas Instruments THMC50
+	  sensor chips and clones: the Analog Devices ADM1022.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called thmc50.
+
+config SENSORS_TMP102
+	tristate "Texas Instruments TMP102"
+	depends on I2C
+	depends on THERMAL || !THERMAL_OF
+	help
+	  If you say yes here you get support for Texas Instruments TMP102
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tmp102.
+
+config SENSORS_TMP103
+	tristate "Texas Instruments TMP103"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for Texas Instruments TMP103
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tmp103.
+
+config SENSORS_TMP401
+	tristate "Texas Instruments TMP401 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for Texas Instruments TMP401,
+	  TMP411, TMP431, TMP432 and TMP435 temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tmp401.
+
+config SENSORS_TMP421
+	tristate "Texas Instruments TMP421 and compatible"
+	depends on I2C
+	help
+	  If you say yes here you get support for Texas Instruments TMP421,
+	  TMP422, TMP423, TMP441, and TMP442 temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tmp421.
+
+config SENSORS_TWL4030_MADC
+	tristate "Texas Instruments TWL4030 MADC Hwmon"
+	depends on TWL4030_MADC
+	help
+	If you say yes here you get hwmon support for triton
+	TWL4030-MADC.
+
+	This driver can also be built as a module. If so it will be called
+	twl4030-madc-hwmon.
+
+config SENSORS_VEXPRESS
+	tristate "Versatile Express"
+	depends on VEXPRESS_CONFIG
+	help
+	  This driver provides support for hardware sensors available on
+	  the ARM Ltd's Versatile Express platform. It can provide wide
+	  range of information like temperature, power, energy.
+
+config SENSORS_VIA_CPUTEMP
+	tristate "VIA CPU temperature sensor"
+	depends on X86
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the temperature
+	  sensor inside your CPU. Supported are all known variants of
+	  the VIA C7 and Nano.
+
+config SENSORS_VIA686A
+	tristate "VIA686A"
+	depends on PCI
+	help
+	  If you say yes here you get support for the integrated sensors in
+	  Via 686A/B South Bridges.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called via686a.
+
+config SENSORS_VT1211
+	tristate "VIA VT1211"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here then you get support for hardware monitoring
+	  features of the VIA VT1211 Super-I/O chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called vt1211.
+
+config SENSORS_VT8231
+	tristate "VIA VT8231"
+	depends on PCI
+	select HWMON_VID
+	help
+	  If you say yes here then you get support for the integrated sensors
+	  in the VIA VT8231 device.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called vt8231.
+
+config SENSORS_W83781D
+	tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Winbond W8378x series
+	  of sensor chips: the W83781D, W83782D and W83783S, and the similar
+	  Asus AS99127F.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83781d.
+
+config SENSORS_W83791D
+	tristate "Winbond W83791D"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Winbond W83791D chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83791d.
+
+config SENSORS_W83792D
+	tristate "Winbond W83792D"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Winbond W83792D chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83792d.
+
+config SENSORS_W83793
+	tristate "Winbond W83793"
+	depends on I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Winbond W83793
+	  hardware monitoring chip, including support for the integrated
+	  watchdog.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83793.
+
+config SENSORS_W83795
+	tristate "Winbond/Nuvoton W83795G/ADG"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Winbond W83795G and
+	  W83795ADG hardware monitoring chip, including manual fan speed
+	  control.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83795.
+
+config SENSORS_W83795_FANCTRL
+	bool "Include automatic fan control support (DANGEROUS)"
+	depends on SENSORS_W83795
+	default n
+	help
+	  If you say yes here, support for automatic fan speed control
+	  will be included in the driver.
+
+	  This part of the code wasn't carefully reviewed and tested yet,
+	  so enabling this option is strongly discouraged on production
+	  servers. Only developers and testers should enable it for the
+	  time being.
+
+	  Please also note that this option will create sysfs attribute
+	  files which may change in the future, so you shouldn't rely
+	  on them being stable.
+
+config SENSORS_W83L785TS
+	tristate "Winbond W83L785TS-S"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Winbond W83L785TS-S
+	  sensor chip, which is used on the Asus A7N8X, among other
+	  motherboards.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83l785ts.
+
+config SENSORS_W83L786NG
+	tristate "Winbond W83L786NG, W83L786NR"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Winbond W83L786NG
+	  and W83L786NR sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83l786ng.
+
+config SENSORS_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the Winbond W836X7 series
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf.
+
+config SENSORS_W83627EHF
+	tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG, NCT6775F, NCT6776F"
+	depends on !PPC
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the hardware
+	  monitoring functionality of the Winbond W83627EHF Super-I/O chip.
+
+	  This driver also supports the W83627EHG, which is the lead-free
+	  version of the W83627EHF, and the W83627DHG, which is a similar
+	  chip suited for specific Intel processors that use PECI such as
+	  the Core 2 Duo. And also the W83627UHG, which is a stripped down
+	  version of the W83627DHG (as far as hardware monitoring goes.)
+
+	  This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F
+	  (also known as W83667HG-I), and NCT6776F.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627ehf.
+
+config SENSORS_WM831X
+	tristate "WM831x PMICs"
+	depends on MFD_WM831X
+	help
+	  If you say yes here you get support for the hardware
+	  monitoring functionality of the Wolfson Microelectronics
+	  WM831x series of PMICs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called wm831x-hwmon.
+
+config SENSORS_WM8350
+	tristate "Wolfson Microelectronics WM835x"
+	depends on MFD_WM8350
+	help
+	  If you say yes here you get support for the hardware
+	  monitoring features of the WM835x series of PMICs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called wm8350-hwmon.
+
+config SENSORS_ULTRA45
+	tristate "Sun Ultra45 PIC16F747"
+	depends on SPARC64
+	help
+	  This driver provides support for the Ultra45 workstation environmental
+	  sensors.
+
+if ACPI
+
+comment "ACPI drivers"
+
+config SENSORS_ACPI_POWER
+	tristate "ACPI 4.0 power meter"
+	help
+	  This driver exposes ACPI 4.0 power meters as hardware monitoring
+	  devices.  Say Y (or M) if you have a computer with ACPI 4.0 firmware
+	  and a power meter.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called acpi_power_meter.
+
+config SENSORS_ATK0110
+	tristate "ASUS ATK0110"
+	depends on X86
+	help
+	  If you say yes here you get support for the ACPI hardware
+	  monitoring interface found in many ASUS motherboards. This
+	  driver will provide readings of fans, voltages and temperatures
+	  through the system firmware.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called asus_atk0110.
+
+endif # ACPI
+
+endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
new file mode 100644
index 0000000..12a3239
--- /dev/null
+++ b/drivers/hwmon/Makefile
@@ -0,0 +1,167 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_HWMON)		+= hwmon.o
+obj-$(CONFIG_HWMON_VID)		+= hwmon-vid.o
+
+# APCI drivers
+obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
+obj-$(CONFIG_SENSORS_ATK0110)	+= asus_atk0110.o
+
+# Native drivers
+# asb100, then w83781d go first, as they can override other drivers' addresses.
+obj-$(CONFIG_SENSORS_ASB100)	+= asb100.o
+obj-$(CONFIG_SENSORS_W83627HF)	+= w83627hf.o
+obj-$(CONFIG_SENSORS_W83792D)	+= w83792d.o
+obj-$(CONFIG_SENSORS_W83793)	+= w83793.o
+obj-$(CONFIG_SENSORS_W83795)	+= w83795.o
+obj-$(CONFIG_SENSORS_W83781D)	+= w83781d.o
+obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
+
+obj-$(CONFIG_SENSORS_AB8500)	+= abx500.o ab8500.o
+obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
+obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7314)	+= ad7314.o
+obj-$(CONFIG_SENSORS_AD7414)	+= ad7414.o
+obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
+obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
+obj-$(CONFIG_SENSORS_ADCXX)	+= adcxx.o
+obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
+obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
+obj-$(CONFIG_SENSORS_ADM1026)	+= adm1026.o
+obj-$(CONFIG_SENSORS_ADM1029)	+= adm1029.o
+obj-$(CONFIG_SENSORS_ADM1031)	+= adm1031.o
+obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
+obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
+obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
+obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
+obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
+obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
+obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
+obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
+obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
+obj-$(CONFIG_SENSORS_ADT7470)	+= adt7470.o
+obj-$(CONFIG_SENSORS_ADT7475)	+= adt7475.o
+obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
+obj-$(CONFIG_SENSORS_ARM_SCPI)	+= scpi-hwmon.o
+obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
+obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
+obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
+obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
+obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
+obj-$(CONFIG_SENSORS_DELL_SMM)	+= dell-smm-hwmon.o
+obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
+obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
+obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
+obj-$(CONFIG_SENSORS_EMC1403)	+= emc1403.o
+obj-$(CONFIG_SENSORS_EMC2103)	+= emc2103.o
+obj-$(CONFIG_SENSORS_EMC6W201)	+= emc6w201.o
+obj-$(CONFIG_SENSORS_F71805F)	+= f71805f.o
+obj-$(CONFIG_SENSORS_F71882FG)	+= f71882fg.o
+obj-$(CONFIG_SENSORS_F75375S)	+= f75375s.o
+obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
+obj-$(CONFIG_SENSORS_FSCHMD)	+= fschmd.o
+obj-$(CONFIG_SENSORS_G760A)	+= g760a.o
+obj-$(CONFIG_SENSORS_G762)	+= g762.o
+obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
+obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
+obj-$(CONFIG_SENSORS_GPIO_FAN)	+= gpio-fan.o
+obj-$(CONFIG_SENSORS_HIH6130)	+= hih6130.o
+obj-$(CONFIG_SENSORS_HTU21)	+= htu21.o
+obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
+obj-$(CONFIG_SENSORS_I5500)	+= i5500_temp.o
+obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
+obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
+obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
+obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
+obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
+obj-$(CONFIG_SENSORS_INA209)	+= ina209.o
+obj-$(CONFIG_SENSORS_INA2XX)	+= ina2xx.o
+obj-$(CONFIG_SENSORS_IT87)	+= it87.o
+obj-$(CONFIG_SENSORS_JC42)	+= jc42.o
+obj-$(CONFIG_SENSORS_JZ4740)	+= jz4740-hwmon.o
+obj-$(CONFIG_SENSORS_K8TEMP)	+= k8temp.o
+obj-$(CONFIG_SENSORS_K10TEMP)	+= k10temp.o
+obj-$(CONFIG_SENSORS_LINEAGE)	+= lineage-pem.o
+obj-$(CONFIG_SENSORS_LM63)	+= lm63.o
+obj-$(CONFIG_SENSORS_LM70)	+= lm70.o
+obj-$(CONFIG_SENSORS_LM73)	+= lm73.o
+obj-$(CONFIG_SENSORS_LM75)	+= lm75.o
+obj-$(CONFIG_SENSORS_LM77)	+= lm77.o
+obj-$(CONFIG_SENSORS_LM78)	+= lm78.o
+obj-$(CONFIG_SENSORS_LM80)	+= lm80.o
+obj-$(CONFIG_SENSORS_LM83)	+= lm83.o
+obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
+obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
+obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
+obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
+obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
+obj-$(CONFIG_SENSORS_LM95234)	+= lm95234.o
+obj-$(CONFIG_SENSORS_LM95241)	+= lm95241.o
+obj-$(CONFIG_SENSORS_LM95245)	+= lm95245.o
+obj-$(CONFIG_SENSORS_LTC2945)	+= ltc2945.o
+obj-$(CONFIG_SENSORS_LTC4151)	+= ltc4151.o
+obj-$(CONFIG_SENSORS_LTC4215)	+= ltc4215.o
+obj-$(CONFIG_SENSORS_LTC4222)	+= ltc4222.o
+obj-$(CONFIG_SENSORS_LTC4245)	+= ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4260)	+= ltc4260.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_MAX1668)	+= max1668.o
+obj-$(CONFIG_SENSORS_MAX197)	+= max197.o
+obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o
+obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o
+obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
+obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o
+obj-$(CONFIG_SENSORS_MAX31790)	+= max31790.o
+obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
+obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o
+obj-$(CONFIG_SENSORS_NCT6683)	+= nct6683.o
+obj-$(CONFIG_SENSORS_NCT6775)	+= nct6775.o
+obj-$(CONFIG_SENSORS_NCT7802)	+= nct7802.o
+obj-$(CONFIG_SENSORS_NCT7904)	+= nct7904.o
+obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
+obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
+obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
+obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+obj-$(CONFIG_SENSORS_POWR1220)  += powr1220.o
+obj-$(CONFIG_SENSORS_PWM_FAN)	+= pwm-fan.o
+obj-$(CONFIG_SENSORS_S3C)	+= s3c-hwmon.o
+obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
+obj-$(CONFIG_SENSORS_SCH5627)	+= sch5627.o
+obj-$(CONFIG_SENSORS_SCH5636)	+= sch5636.o
+obj-$(CONFIG_SENSORS_SHT15)	+= sht15.o
+obj-$(CONFIG_SENSORS_SHT21)	+= sht21.o
+obj-$(CONFIG_SENSORS_SHTC1)	+= shtc1.o
+obj-$(CONFIG_SENSORS_SIS5595)	+= sis5595.o
+obj-$(CONFIG_SENSORS_SMM665)	+= smm665.o
+obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
+obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47m1.o
+obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+obj-$(CONFIG_SENSORS_AMC6821)	+= amc6821.o
+obj-$(CONFIG_SENSORS_TC74)	+= tc74.o
+obj-$(CONFIG_SENSORS_THMC50)	+= thmc50.o
+obj-$(CONFIG_SENSORS_TMP102)	+= tmp102.o
+obj-$(CONFIG_SENSORS_TMP103)	+= tmp103.o
+obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
+obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
+obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
+obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress.o
+obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
+obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
+obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
+obj-$(CONFIG_SENSORS_VT8231)	+= vt8231.o
+obj-$(CONFIG_SENSORS_W83627EHF)	+= w83627ehf.o
+obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
+obj-$(CONFIG_SENSORS_W83L786NG)	+= w83l786ng.o
+obj-$(CONFIG_SENSORS_WM831X)	+= wm831x-hwmon.o
+obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
+
+obj-$(CONFIG_PMBUS)		+= pmbus/
+
+ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
+
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c
new file mode 100644
index 0000000..8b6a4f4
--- /dev/null
+++ b/drivers/hwmon/ab8500.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ *         Hongbo Zhang <hongbo.zhang@linaro.org>
+ * License Terms: GNU General Public License v2
+ *
+ * When the AB8500 thermal warning temperature is reached (threshold cannot
+ * be changed by SW), an interrupt is set, and if no further action is taken
+ * within a certain time frame, kernel_power_off will be called.
+ *
+ * When AB8500 thermal shutdown temperature is reached a hardware shutdown of
+ * the AB8500 will occur.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/ab8500.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include "abx500.h"
+
+#define DEFAULT_POWER_OFF_DELAY	(HZ * 10)
+#define THERMAL_VCC		1800
+#define PULL_UP_RESISTOR	47000
+/* Number of monitored sensors should not greater than NUM_SENSORS */
+#define NUM_MONITORED_SENSORS	4
+
+struct ab8500_gpadc_cfg {
+	const struct abx500_res_to_temp *temp_tbl;
+	int tbl_sz;
+	int vcc;
+	int r_up;
+};
+
+struct ab8500_temp {
+	struct ab8500_gpadc *gpadc;
+	struct ab8500_btemp *btemp;
+	struct delayed_work power_off_work;
+	struct ab8500_gpadc_cfg cfg;
+	struct abx500_temp *abx500_data;
+};
+
+/*
+ * The hardware connection is like this:
+ * VCC----[ R_up ]-----[ NTC ]----GND
+ * where R_up is pull-up resistance, and GPADC measures voltage on NTC.
+ * and res_to_temp table is strictly sorted by falling resistance values.
+ */
+static int ab8500_voltage_to_temp(struct ab8500_gpadc_cfg *cfg,
+		int v_ntc, int *temp)
+{
+	int r_ntc, i = 0, tbl_sz = cfg->tbl_sz;
+	const struct abx500_res_to_temp *tbl = cfg->temp_tbl;
+
+	if (cfg->vcc < 0 || v_ntc >= cfg->vcc)
+		return -EINVAL;
+
+	r_ntc = v_ntc * cfg->r_up / (cfg->vcc - v_ntc);
+	if (r_ntc > tbl[0].resist || r_ntc < tbl[tbl_sz - 1].resist)
+		return -EINVAL;
+
+	while (!(r_ntc <= tbl[i].resist && r_ntc > tbl[i + 1].resist) &&
+			i < tbl_sz - 2)
+		i++;
+
+	/* return milli-Celsius */
+	*temp = tbl[i].temp * 1000 + ((tbl[i + 1].temp - tbl[i].temp) * 1000 *
+		(r_ntc - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
+
+	return 0;
+}
+
+static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp)
+{
+	int voltage, ret;
+	struct ab8500_temp *ab8500_data = data->plat_data;
+
+	if (sensor == BAT_CTRL) {
+		*temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
+	} else if (sensor == BTEMP_BALL) {
+		*temp = ab8500_btemp_get_temp(ab8500_data->btemp);
+	} else {
+		voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor);
+		if (voltage < 0)
+			return voltage;
+
+		ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void ab8500_thermal_power_off(struct work_struct *work)
+{
+	struct ab8500_temp *ab8500_data = container_of(work,
+				struct ab8500_temp, power_off_work.work);
+	struct abx500_temp *abx500_data = ab8500_data->abx500_data;
+
+	dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n");
+
+	kernel_power_off();
+}
+
+static ssize_t ab8500_show_name(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "ab8500\n");
+}
+
+static ssize_t ab8500_show_label(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	char *label;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int index = attr->index;
+
+	switch (index) {
+	case 1:
+		label = "ext_adc1";
+		break;
+	case 2:
+		label = "ext_adc2";
+		break;
+	case 3:
+		label = "bat_temp";
+		break;
+	case 4:
+		label = "bat_ctrl";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sprintf(buf, "%s\n", label);
+}
+
+static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data)
+{
+	struct ab8500_temp *ab8500_data = data->plat_data;
+
+	dev_warn(&data->pdev->dev, "Power off in %d s\n",
+		 DEFAULT_POWER_OFF_DELAY / HZ);
+
+	schedule_delayed_work(&ab8500_data->power_off_work,
+		DEFAULT_POWER_OFF_DELAY);
+	return 0;
+}
+
+int abx500_hwmon_init(struct abx500_temp *data)
+{
+	struct ab8500_temp *ab8500_data;
+
+	ab8500_data = devm_kzalloc(&data->pdev->dev, sizeof(*ab8500_data),
+		GFP_KERNEL);
+	if (!ab8500_data)
+		return -ENOMEM;
+
+	ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	if (IS_ERR(ab8500_data->gpadc))
+		return PTR_ERR(ab8500_data->gpadc);
+
+	ab8500_data->btemp = ab8500_btemp_get();
+	if (IS_ERR(ab8500_data->btemp))
+		return PTR_ERR(ab8500_data->btemp);
+
+	INIT_DELAYED_WORK(&ab8500_data->power_off_work,
+			  ab8500_thermal_power_off);
+
+	ab8500_data->cfg.vcc = THERMAL_VCC;
+	ab8500_data->cfg.r_up = PULL_UP_RESISTOR;
+	ab8500_data->cfg.temp_tbl = ab8500_temp_tbl_a_thermistor;
+	ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size;
+
+	data->plat_data = ab8500_data;
+
+	/*
+	 * ADC_AUX1 and ADC_AUX2, connected to external NTC
+	 * BTEMP_BALL and BAT_CTRL, fixed usage
+	 */
+	data->gpadc_addr[0] = ADC_AUX1;
+	data->gpadc_addr[1] = ADC_AUX2;
+	data->gpadc_addr[2] = BTEMP_BALL;
+	data->gpadc_addr[3] = BAT_CTRL;
+	data->monitored_sensors = NUM_MONITORED_SENSORS;
+
+	data->ops.read_sensor = ab8500_read_sensor;
+	data->ops.irq_handler = ab8500_temp_irq_handler;
+	data->ops.show_name = ab8500_show_name;
+	data->ops.show_label = ab8500_show_label;
+	data->ops.is_visible = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(abx500_hwmon_init);
+
+MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@linaro.org>");
+MODULE_DESCRIPTION("AB8500 temperature driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
new file mode 100644
index 0000000..7a09c16
--- /dev/null
+++ b/drivers/hwmon/abituguru.c
@@ -0,0 +1,1650 @@
+/*
+ * abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com>
+ *
+ * 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.
+ */
+/*
+ * This driver supports the sensor part of the first and second revision of
+ * the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
+ * of lack of specs the CPU/RAM voltage & frequency control is not supported!
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+
+/* Banks */
+#define ABIT_UGURU_ALARM_BANK			0x20 /* 1x 3 bytes */
+#define ABIT_UGURU_SENSOR_BANK1			0x21 /* 16x volt and temp */
+#define ABIT_UGURU_FAN_PWM			0x24 /* 3x 5 bytes */
+#define ABIT_UGURU_SENSOR_BANK2			0x26 /* fans */
+/* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */
+#define ABIT_UGURU_MAX_BANK1_SENSORS		16
+/*
+ * Warning if you increase one of the 2 MAX defines below to 10 or higher you
+ * should adjust the belonging _NAMES_LENGTH macro for the 2 digit number!
+ */
+/* max nr of sensors in bank2, currently mb's with max 6 fans are known */
+#define ABIT_UGURU_MAX_BANK2_SENSORS		6
+/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
+#define ABIT_UGURU_MAX_PWMS			5
+/* uGuru sensor bank 1 flags */			     /* Alarm if: */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE	0x01 /*  temp over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE	0x02 /*  volt over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE	0x04 /*  volt under min */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG		0x10 /* temp is over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG		0x20 /* volt is over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_FLAG		0x40 /* volt is under min */
+/* uGuru sensor bank 2 flags */			     /* Alarm if: */
+#define ABIT_UGURU_FAN_LOW_ALARM_ENABLE		0x01 /*   fan under min */
+/* uGuru sensor bank common flags */
+#define ABIT_UGURU_BEEP_ENABLE			0x08 /* beep if alarm */
+#define ABIT_UGURU_SHUTDOWN_ENABLE		0x80 /* shutdown if alarm */
+/* uGuru fan PWM (speed control) flags */
+#define ABIT_UGURU_FAN_PWM_ENABLE		0x80 /* enable speed control */
+/* Values used for conversion */
+#define ABIT_UGURU_FAN_MAX			15300 /* RPM */
+/* Bank1 sensor types */
+#define ABIT_UGURU_IN_SENSOR			0
+#define ABIT_UGURU_TEMP_SENSOR			1
+#define ABIT_UGURU_NC				2
+/*
+ * In many cases we need to wait for the uGuru to reach a certain status, most
+ * of the time it will reach this status within 30 - 90 ISA reads, and thus we
+ * can best busy wait. This define gives the total amount of reads to try.
+ */
+#define ABIT_UGURU_WAIT_TIMEOUT			125
+/*
+ * However sometimes older versions of the uGuru seem to be distracted and they
+ * do not respond for a long time. To handle this we sleep before each of the
+ * last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries.
+ */
+#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP		5
+/*
+ * Normally all expected status in abituguru_ready, are reported after the
+ * first read, but sometimes not and we need to poll.
+ */
+#define ABIT_UGURU_READY_TIMEOUT		5
+/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
+#define ABIT_UGURU_MAX_RETRIES			3
+#define ABIT_UGURU_RETRY_DELAY			(HZ/5)
+/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is an error */
+#define ABIT_UGURU_MAX_TIMEOUTS			2
+/* utility macros */
+#define ABIT_UGURU_NAME				"abituguru"
+#define ABIT_UGURU_DEBUG(level, format, arg...)		\
+	do {						\
+		if (level <= verbose)			\
+			pr_debug(format , ## arg);	\
+	} while (0)
+
+/* Macros to help calculate the sysfs_names array length */
+/*
+ * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+ * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0
+ */
+#define ABITUGURU_IN_NAMES_LENGTH	(11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14)
+/*
+ * sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0,
+ * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0
+ */
+#define ABITUGURU_TEMP_NAMES_LENGTH	(13 + 11 + 12 + 13 + 20 + 12 + 16)
+/*
+ * sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0,
+ * fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0
+ */
+#define ABITUGURU_FAN_NAMES_LENGTH	(11 + 9 + 11 + 18 + 10 + 14)
+/*
+ * sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0,
+ * pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0
+ */
+#define ABITUGURU_PWM_NAMES_LENGTH	(12 + 24 + 2 * 21 + 2 * 22)
+/* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */
+#define ABITUGURU_SYSFS_NAMES_LENGTH	( \
+	ABIT_UGURU_MAX_BANK1_SENSORS * ABITUGURU_IN_NAMES_LENGTH + \
+	ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \
+	ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH)
+
+/*
+ * All the macros below are named identical to the oguru and oguru2 programs
+ * reverse engineered by Olle Sandberg, hence the names might not be 100%
+ * logical. I could come up with better names, but I prefer keeping the names
+ * identical so that this driver can be compared with his work more easily.
+ */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU_BASE				0x00E0
+/* Used to tell uGuru what to read and to read the actual data */
+#define ABIT_UGURU_CMD				0x00
+/* Mostly used to check if uGuru is busy */
+#define ABIT_UGURU_DATA				0x04
+#define ABIT_UGURU_REGION_LENGTH		5
+/* uGuru status' */
+#define ABIT_UGURU_STATUS_WRITE			0x00 /* Ready to be written */
+#define ABIT_UGURU_STATUS_READ			0x01 /* Ready to be read */
+#define ABIT_UGURU_STATUS_INPUT			0x08 /* More input */
+#define ABIT_UGURU_STATUS_READY			0x09 /* Ready to be written */
+
+/* Constants */
+/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
+static const int abituguru_bank1_max_value[2] = { 3494, 255000 };
+/*
+ * Min / Max allowed values for sensor2 (fan) alarm threshold, these values
+ * correspond to 300-3000 RPM
+ */
+static const u8 abituguru_bank2_min_threshold = 5;
+static const u8 abituguru_bank2_max_threshold = 50;
+/*
+ * Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
+ * are temperature trip points.
+ */
+static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 };
+/*
+ * Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
+ * special case the minimum allowed pwm% setting for this is 30% (77) on
+ * some MB's this special case is handled in the code!
+ */
+static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 };
+static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
+
+
+/* Insmod parameters */
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+module_param_array(bank1_types, int, NULL, 0);
+MODULE_PARM_DESC(bank1_types, "Bank1 sensortype autodetection override:\n"
+	"   -1 autodetect\n"
+	"    0 volt sensor\n"
+	"    1 temp sensor\n"
+	"    2 not connected");
+static int fan_sensors;
+module_param(fan_sensors, int, 0);
+MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
+	"(0 = autodetect)");
+static int pwms;
+module_param(pwms, int, 0);
+MODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru "
+	"(0 = autodetect)");
+
+/* Default verbose is 2, since this driver is still in the testing phase */
+static int verbose = 2;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
+	"   0 normal output\n"
+	"   1 + verbose error reporting\n"
+	"   2 + sensors type probing info\n"
+	"   3 + retryable error reporting");
+
+
+/*
+ * For the Abit uGuru, we need to keep some data in memory.
+ * The structure is dynamically allocated, at the same time when a new
+ * abituguru device is allocated.
+ */
+struct abituguru_data {
+	struct device *hwmon_dev;	/* hwmon registered device */
+	struct mutex update_lock;	/* protect access to data and uGuru */
+	unsigned long last_updated;	/* In jiffies */
+	unsigned short addr;		/* uguru base address */
+	char uguru_ready;		/* is the uguru in ready state? */
+	unsigned char update_timeouts;	/*
+					 * number of update timeouts since last
+					 * successful update
+					 */
+
+	/*
+	 * The sysfs attr and their names are generated automatically, for bank1
+	 * we cannot use a predefined array because we don't know beforehand
+	 * of a sensor is a volt or a temp sensor, for bank2 and the pwms its
+	 * easier todo things the same way.  For in sensors we have 9 (temp 7)
+	 * sysfs entries per sensor, for bank2 and pwms 6.
+	 */
+	struct sensor_device_attribute_2 sysfs_attr[
+		ABIT_UGURU_MAX_BANK1_SENSORS * 9 +
+		ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
+	/* Buffer to store the dynamically generated sysfs names */
+	char sysfs_names[ABITUGURU_SYSFS_NAMES_LENGTH];
+
+	/* Bank 1 data */
+	/* number of and addresses of [0] in, [1] temp sensors */
+	u8 bank1_sensors[2];
+	u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS];
+	u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS];
+	/*
+	 * This array holds 3 entries per sensor for the bank 1 sensor settings
+	 * (flags, min, max for voltage / flags, warn, shutdown for temp).
+	 */
+	u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3];
+	/*
+	 * Maximum value for each sensor used for scaling in mV/millidegrees
+	 * Celsius.
+	 */
+	int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS];
+
+	/* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
+	u8 bank2_sensors; /* actual number of bank2 sensors found */
+	u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS];
+	u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */
+
+	/* Alarms 2 bytes for bank1, 1 byte for bank2 */
+	u8 alarms[3];
+
+	/* Fan PWM (speed control) 5 bytes per PWM */
+	u8 pwms; /* actual number of pwms found */
+	u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
+};
+
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+	"Please report this to the abituguru maintainer (see MAINTAINERS)";
+
+/* wait till the uguru is in the specified state */
+static int abituguru_wait(struct abituguru_data *data, u8 state)
+{
+	int timeout = ABIT_UGURU_WAIT_TIMEOUT;
+
+	while (inb_p(data->addr + ABIT_UGURU_DATA) != state) {
+		timeout--;
+		if (timeout == 0)
+			return -EBUSY;
+		/*
+		 * sleep a bit before our last few tries, see the comment on
+		 * this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined.
+		 */
+		if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP)
+			msleep(0);
+	}
+	return 0;
+}
+
+/* Put the uguru in ready for input state */
+static int abituguru_ready(struct abituguru_data *data)
+{
+	int timeout = ABIT_UGURU_READY_TIMEOUT;
+
+	if (data->uguru_ready)
+		return 0;
+
+	/* Reset? / Prepare for next read/write cycle */
+	outb(0x00, data->addr + ABIT_UGURU_DATA);
+
+	/* Wait till the uguru is ready */
+	if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) {
+		ABIT_UGURU_DEBUG(1,
+			"timeout exceeded waiting for ready state\n");
+		return -EIO;
+	}
+
+	/* Cmd port MUST be read now and should contain 0xAC */
+	while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+		timeout--;
+		if (timeout == 0) {
+			ABIT_UGURU_DEBUG(1,
+			   "CMD reg does not hold 0xAC after ready command\n");
+			return -EIO;
+		}
+		msleep(0);
+	}
+
+	/*
+	 * After this the ABIT_UGURU_DATA port should contain
+	 * ABIT_UGURU_STATUS_INPUT
+	 */
+	timeout = ABIT_UGURU_READY_TIMEOUT;
+	while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) {
+		timeout--;
+		if (timeout == 0) {
+			ABIT_UGURU_DEBUG(1,
+				"state != more input after ready command\n");
+			return -EIO;
+		}
+		msleep(0);
+	}
+
+	data->uguru_ready = 1;
+	return 0;
+}
+
+/*
+ * Send the bank and then sensor address to the uGuru for the next read/write
+ * cycle. This function gets called as the first part of a read/write by
+ * abituguru_read and abituguru_write. This function should never be
+ * called by any other function.
+ */
+static int abituguru_send_address(struct abituguru_data *data,
+	u8 bank_addr, u8 sensor_addr, int retries)
+{
+	/*
+	 * assume the caller does error handling itself if it has not requested
+	 * any retries, and thus be quiet.
+	 */
+	int report_errors = retries;
+
+	for (;;) {
+		/*
+		 * Make sure the uguru is ready and then send the bank address,
+		 * after this the uguru is no longer "ready".
+		 */
+		if (abituguru_ready(data) != 0)
+			return -EIO;
+		outb(bank_addr, data->addr + ABIT_UGURU_DATA);
+		data->uguru_ready = 0;
+
+		/*
+		 * Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
+		 * and send the sensor addr
+		 */
+		if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) {
+			if (retries) {
+				ABIT_UGURU_DEBUG(3, "timeout exceeded "
+					"waiting for more input state, %d "
+					"tries remaining\n", retries);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout(ABIT_UGURU_RETRY_DELAY);
+				retries--;
+				continue;
+			}
+			if (report_errors)
+				ABIT_UGURU_DEBUG(1, "timeout exceeded "
+					"waiting for more input state "
+					"(bank: %d)\n", (int)bank_addr);
+			return -EBUSY;
+		}
+		outb(sensor_addr, data->addr + ABIT_UGURU_CMD);
+		return 0;
+	}
+}
+
+/*
+ * Read count bytes from sensor sensor_addr in bank bank_addr and store the
+ * result in buf, retry the send address part of the read retries times.
+ */
+static int abituguru_read(struct abituguru_data *data,
+	u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries)
+{
+	int i;
+
+	/* Send the address */
+	i = abituguru_send_address(data, bank_addr, sensor_addr, retries);
+	if (i)
+		return i;
+
+	/* And read the data */
+	for (i = 0; i < count; i++) {
+		if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+			ABIT_UGURU_DEBUG(retries ? 1 : 3,
+				"timeout exceeded waiting for "
+				"read state (bank: %d, sensor: %d)\n",
+				(int)bank_addr, (int)sensor_addr);
+			break;
+		}
+		buf[i] = inb(data->addr + ABIT_UGURU_CMD);
+	}
+
+	/* Last put the chip back in ready state */
+	abituguru_ready(data);
+
+	return i;
+}
+
+/*
+ * Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
+ * address part of the write is always retried ABIT_UGURU_MAX_RETRIES times.
+ */
+static int abituguru_write(struct abituguru_data *data,
+	u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
+{
+	/*
+	 * We use the ready timeout as we have to wait for 0xAC just like the
+	 * ready function
+	 */
+	int i, timeout = ABIT_UGURU_READY_TIMEOUT;
+
+	/* Send the address */
+	i = abituguru_send_address(data, bank_addr, sensor_addr,
+		ABIT_UGURU_MAX_RETRIES);
+	if (i)
+		return i;
+
+	/* And write the data */
+	for (i = 0; i < count; i++) {
+		if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) {
+			ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+				"write state (bank: %d, sensor: %d)\n",
+				(int)bank_addr, (int)sensor_addr);
+			break;
+		}
+		outb(buf[i], data->addr + ABIT_UGURU_CMD);
+	}
+
+	/*
+	 * Now we need to wait till the chip is ready to be read again,
+	 * so that we can read 0xAC as confirmation that our write has
+	 * succeeded.
+	 */
+	if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+		ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
+			"after write (bank: %d, sensor: %d)\n", (int)bank_addr,
+			(int)sensor_addr);
+		return -EIO;
+	}
+
+	/* Cmd port MUST be read now and should contain 0xAC */
+	while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+		timeout--;
+		if (timeout == 0) {
+			ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after "
+				"write (bank: %d, sensor: %d)\n",
+				(int)bank_addr, (int)sensor_addr);
+			return -EIO;
+		}
+		msleep(0);
+	}
+
+	/* Last put the chip back in ready state */
+	abituguru_ready(data);
+
+	return i;
+}
+
+/*
+ * Detect sensor type. Temp and Volt sensors are enabled with
+ * different masks and will ignore enable masks not meant for them.
+ * This enables us to test what kind of sensor we're dealing with.
+ * By setting the alarm thresholds so that we will always get an
+ * alarm for sensor type X and then enabling the sensor as sensor type
+ * X, if we then get an alarm it is a sensor of type X.
+ */
+static int
+abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
+				   u8 sensor_addr)
+{
+	u8 val, test_flag, buf[3];
+	int i, ret = -ENODEV; /* error is the most common used retval :| */
+
+	/* If overriden by the user return the user selected type */
+	if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR &&
+			bank1_types[sensor_addr] <= ABIT_UGURU_NC) {
+		ABIT_UGURU_DEBUG(2, "assuming sensor type %d for bank1 sensor "
+			"%d because of \"bank1_types\" module param\n",
+			bank1_types[sensor_addr], (int)sensor_addr);
+		return bank1_types[sensor_addr];
+	}
+
+	/* First read the sensor and the current settings */
+	if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
+			1, ABIT_UGURU_MAX_RETRIES) != 1)
+		return -ENODEV;
+
+	/* Test val is sane / usable for sensor type detection. */
+	if ((val < 10u) || (val > 250u)) {
+		pr_warn("bank1-sensor: %d reading (%d) too close to limits, "
+			"unable to determine sensor type, skipping sensor\n",
+			(int)sensor_addr, (int)val);
+		/*
+		 * assume no sensor is there for sensors for which we can't
+		 * determine the sensor type because their reading is too close
+		 * to their limits, this usually means no sensor is there.
+		 */
+		return ABIT_UGURU_NC;
+	}
+
+	ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
+	/*
+	 * Volt sensor test, enable volt low alarm, set min value ridiculously
+	 * high, or vica versa if the reading is very high. If its a volt
+	 * sensor this should always give us an alarm.
+	 */
+	if (val <= 240u) {
+		buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+		buf[1] = 245;
+		buf[2] = 250;
+		test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
+	} else {
+		buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
+		buf[1] = 5;
+		buf[2] = 10;
+		test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
+	}
+
+	if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+			buf, 3) != 3)
+		goto abituguru_detect_bank1_sensor_type_exit;
+	/*
+	 * Now we need 20 ms to give the uguru time to read the sensors
+	 * and raise a voltage alarm
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/50);
+	/* Check for alarm and check the alarm is a volt low alarm. */
+	if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+			ABIT_UGURU_MAX_RETRIES) != 3)
+		goto abituguru_detect_bank1_sensor_type_exit;
+	if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+				sensor_addr, buf, 3,
+				ABIT_UGURU_MAX_RETRIES) != 3)
+			goto abituguru_detect_bank1_sensor_type_exit;
+		if (buf[0] & test_flag) {
+			ABIT_UGURU_DEBUG(2, "  found volt sensor\n");
+			ret = ABIT_UGURU_IN_SENSOR;
+			goto abituguru_detect_bank1_sensor_type_exit;
+		} else
+			ABIT_UGURU_DEBUG(2, "  alarm raised during volt "
+				"sensor test, but volt range flag not set\n");
+	} else
+		ABIT_UGURU_DEBUG(2, "  alarm not raised during volt sensor "
+			"test\n");
+
+	/*
+	 * Temp sensor test, enable sensor as a temp sensor, set beep value
+	 * ridiculously low (but not too low, otherwise uguru ignores it).
+	 * If its a temp sensor this should always give us an alarm.
+	 */
+	buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE;
+	buf[1] = 5;
+	buf[2] = 10;
+	if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+			buf, 3) != 3)
+		goto abituguru_detect_bank1_sensor_type_exit;
+	/*
+	 * Now we need 50 ms to give the uguru time to read the sensors
+	 * and raise a temp alarm
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/20);
+	/* Check for alarm and check the alarm is a temp high alarm. */
+	if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+			ABIT_UGURU_MAX_RETRIES) != 3)
+		goto abituguru_detect_bank1_sensor_type_exit;
+	if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+				sensor_addr, buf, 3,
+				ABIT_UGURU_MAX_RETRIES) != 3)
+			goto abituguru_detect_bank1_sensor_type_exit;
+		if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
+			ABIT_UGURU_DEBUG(2, "  found temp sensor\n");
+			ret = ABIT_UGURU_TEMP_SENSOR;
+			goto abituguru_detect_bank1_sensor_type_exit;
+		} else
+			ABIT_UGURU_DEBUG(2, "  alarm raised during temp "
+				"sensor test, but temp high flag not set\n");
+	} else
+		ABIT_UGURU_DEBUG(2, "  alarm not raised during temp sensor "
+			"test\n");
+
+	ret = ABIT_UGURU_NC;
+abituguru_detect_bank1_sensor_type_exit:
+	/*
+	 * Restore original settings, failing here is really BAD, it has been
+	 * reported that some BIOS-es hang when entering the uGuru menu with
+	 * invalid settings present in the uGuru, so we try this 3 times.
+	 */
+	for (i = 0; i < 3; i++)
+		if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+				sensor_addr, data->bank1_settings[sensor_addr],
+				3) == 3)
+			break;
+	if (i == 3) {
+		pr_err("Fatal error could not restore original settings. %s %s\n",
+		       never_happen, report_this);
+		return -ENODEV;
+	}
+	return ret;
+}
+
+/*
+ * These functions try to find out how many sensors there are in bank2 and how
+ * many pwms there are. The purpose of this is to make sure that we don't give
+ * the user the possibility to change settings for non-existent sensors / pwm.
+ * The uGuru will happily read / write whatever memory happens to be after the
+ * memory storing the PWM settings when reading/writing to a PWM which is not
+ * there. Notice even if we detect a PWM which doesn't exist we normally won't
+ * write to it, unless the user tries to change the settings.
+ *
+ * Although the uGuru allows reading (settings) from non existing bank2
+ * sensors, my version of the uGuru does seem to stop writing to them, the
+ * write function above aborts in this case with:
+ * "CMD reg does not hold 0xAC after write"
+ *
+ * Notice these 2 tests are non destructive iow read-only tests, otherwise
+ * they would defeat their purpose. Although for the bank2_sensors detection a
+ * read/write test would be feasible because of the reaction above, I've
+ * however opted to stay on the safe side.
+ */
+static void
+abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
+{
+	int i;
+
+	if (fan_sensors > 0 && fan_sensors <= ABIT_UGURU_MAX_BANK2_SENSORS) {
+		data->bank2_sensors = fan_sensors;
+		ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
+			"\"fan_sensors\" module param\n",
+			(int)data->bank2_sensors);
+		return;
+	}
+
+	ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n");
+	for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+		/*
+		 * 0x89 are the known used bits:
+		 * -0x80 enable shutdown
+		 * -0x08 enable beep
+		 * -0x01 enable alarm
+		 * All other bits should be 0, but on some motherboards
+		 * 0x40 (bit 6) is also high for some of the fans??
+		 */
+		if (data->bank2_settings[i][0] & ~0xC9) {
+			ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+				"to be a fan sensor: settings[0] = %02X\n",
+				i, (unsigned int)data->bank2_settings[i][0]);
+			break;
+		}
+
+		/* check if the threshold is within the allowed range */
+		if (data->bank2_settings[i][1] <
+				abituguru_bank2_min_threshold) {
+			ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+				"to be a fan sensor: the threshold (%d) is "
+				"below the minimum (%d)\n", i,
+				(int)data->bank2_settings[i][1],
+				(int)abituguru_bank2_min_threshold);
+			break;
+		}
+		if (data->bank2_settings[i][1] >
+				abituguru_bank2_max_threshold) {
+			ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+				"to be a fan sensor: the threshold (%d) is "
+				"above the maximum (%d)\n", i,
+				(int)data->bank2_settings[i][1],
+				(int)abituguru_bank2_max_threshold);
+			break;
+		}
+	}
+
+	data->bank2_sensors = i;
+	ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n",
+		(int)data->bank2_sensors);
+}
+
+static void
+abituguru_detect_no_pwms(struct abituguru_data *data)
+{
+	int i, j;
+
+	if (pwms > 0 && pwms <= ABIT_UGURU_MAX_PWMS) {
+		data->pwms = pwms;
+		ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
+			"\"pwms\" module param\n", (int)data->pwms);
+		return;
+	}
+
+	ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n");
+	for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+		/*
+		 * 0x80 is the enable bit and the low
+		 * nibble is which temp sensor to use,
+		 * the other bits should be 0
+		 */
+		if (data->pwm_settings[i][0] & ~0x8F) {
+			ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+				"to be a pwm channel: settings[0] = %02X\n",
+				i, (unsigned int)data->pwm_settings[i][0]);
+			break;
+		}
+
+		/*
+		 * the low nibble must correspond to one of the temp sensors
+		 * we've found
+		 */
+		for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR];
+				j++) {
+			if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] ==
+					(data->pwm_settings[i][0] & 0x0F))
+				break;
+		}
+		if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
+			ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+				"to be a pwm channel: %d is not a valid temp "
+				"sensor address\n", i,
+				data->pwm_settings[i][0] & 0x0F);
+			break;
+		}
+
+		/* check if all other settings are within the allowed range */
+		for (j = 1; j < 5; j++) {
+			u8 min;
+			/* special case pwm1 min pwm% */
+			if ((i == 0) && ((j == 1) || (j == 2)))
+				min = 77;
+			else
+				min = abituguru_pwm_min[j];
+			if (data->pwm_settings[i][j] < min) {
+				ABIT_UGURU_DEBUG(2, "  pwm channel %d does "
+					"not seem to be a pwm channel: "
+					"setting %d (%d) is below the minimum "
+					"value (%d)\n", i, j,
+					(int)data->pwm_settings[i][j],
+					(int)min);
+				goto abituguru_detect_no_pwms_exit;
+			}
+			if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) {
+				ABIT_UGURU_DEBUG(2, "  pwm channel %d does "
+					"not seem to be a pwm channel: "
+					"setting %d (%d) is above the maximum "
+					"value (%d)\n", i, j,
+					(int)data->pwm_settings[i][j],
+					(int)abituguru_pwm_max[j]);
+				goto abituguru_detect_no_pwms_exit;
+			}
+		}
+
+		/* check that min temp < max temp and min pwm < max pwm */
+		if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) {
+			ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+				"to be a pwm channel: min pwm (%d) >= "
+				"max pwm (%d)\n", i,
+				(int)data->pwm_settings[i][1],
+				(int)data->pwm_settings[i][2]);
+			break;
+		}
+		if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) {
+			ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+				"to be a pwm channel: min temp (%d) >= "
+				"max temp (%d)\n", i,
+				(int)data->pwm_settings[i][3],
+				(int)data->pwm_settings[i][4]);
+			break;
+		}
+	}
+
+abituguru_detect_no_pwms_exit:
+	data->pwms = i;
+	ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms);
+}
+
+/*
+ * Following are the sysfs callback functions. These functions expect:
+ * sensor_device_attribute_2->index:   sensor address/offset in the bank
+ * sensor_device_attribute_2->nr:      register offset, bitmask or NA.
+ */
+static struct abituguru_data *abituguru_update_device(struct device *dev);
+
+static ssize_t show_bank1_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = abituguru_update_device(dev);
+	if (!data)
+		return -EIO;
+	return sprintf(buf, "%d\n", (data->bank1_value[attr->index] *
+		data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank1_setting(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		(data->bank1_settings[attr->index][attr->nr] *
+		data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank2_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = abituguru_update_device(dev);
+	if (!data)
+		return -EIO;
+	return sprintf(buf, "%d\n", (data->bank2_value[attr->index] *
+		ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t show_bank2_setting(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		(data->bank2_settings[attr->index][attr->nr] *
+		ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t store_bank1_setting(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = count;
+	val = (val * 255 + data->bank1_max_value[attr->index] / 2) /
+		data->bank1_max_value[attr->index];
+	if (val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (data->bank1_settings[attr->index][attr->nr] != val) {
+		u8 orig_val = data->bank1_settings[attr->index][attr->nr];
+		data->bank1_settings[attr->index][attr->nr] = val;
+		if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+				attr->index, data->bank1_settings[attr->index],
+				3) <= attr->nr) {
+			data->bank1_settings[attr->index][attr->nr] = orig_val;
+			ret = -EIO;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t store_bank2_setting(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = count;
+	val = (val * 255 + ABIT_UGURU_FAN_MAX / 2) / ABIT_UGURU_FAN_MAX;
+
+	/* this check can be done before taking the lock */
+	if (val < abituguru_bank2_min_threshold ||
+			val > abituguru_bank2_max_threshold)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (data->bank2_settings[attr->index][attr->nr] != val) {
+		u8 orig_val = data->bank2_settings[attr->index][attr->nr];
+		data->bank2_settings[attr->index][attr->nr] = val;
+		if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2,
+				attr->index, data->bank2_settings[attr->index],
+				2) <= attr->nr) {
+			data->bank2_settings[attr->index][attr->nr] = orig_val;
+			ret = -EIO;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_bank1_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = abituguru_update_device(dev);
+	if (!data)
+		return -EIO;
+	/*
+	 * See if the alarm bit for this sensor is set, and if the
+	 * alarm matches the type of alarm we're looking for (for volt
+	 * it can be either low or high). The type is stored in a few
+	 * readonly bits in the settings part of the relevant sensor.
+	 * The bitmask of the type is passed to us in attr->nr.
+	 */
+	if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) &&
+			(data->bank1_settings[attr->index][0] & attr->nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = abituguru_update_device(dev);
+	if (!data)
+		return -EIO;
+	if (data->alarms[2] & (0x01 << attr->index))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank1_mask(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	if (data->bank1_settings[attr->index][0] & attr->nr)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_mask(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	if (data->bank2_settings[attr->index][0] & attr->nr)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_bank1_mask(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	ssize_t ret;
+	u8 orig_val;
+	unsigned long mask;
+
+	ret = kstrtoul(buf, 10, &mask);
+	if (ret)
+		return ret;
+
+	ret = count;
+	mutex_lock(&data->update_lock);
+	orig_val = data->bank1_settings[attr->index][0];
+
+	if (mask)
+		data->bank1_settings[attr->index][0] |= attr->nr;
+	else
+		data->bank1_settings[attr->index][0] &= ~attr->nr;
+
+	if ((data->bank1_settings[attr->index][0] != orig_val) &&
+			(abituguru_write(data,
+			ABIT_UGURU_SENSOR_BANK1 + 2, attr->index,
+			data->bank1_settings[attr->index], 3) < 1)) {
+		data->bank1_settings[attr->index][0] = orig_val;
+		ret = -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t store_bank2_mask(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	ssize_t ret;
+	u8 orig_val;
+	unsigned long mask;
+
+	ret = kstrtoul(buf, 10, &mask);
+	if (ret)
+		return ret;
+
+	ret = count;
+	mutex_lock(&data->update_lock);
+	orig_val = data->bank2_settings[attr->index][0];
+
+	if (mask)
+		data->bank2_settings[attr->index][0] |= attr->nr;
+	else
+		data->bank2_settings[attr->index][0] &= ~attr->nr;
+
+	if ((data->bank2_settings[attr->index][0] != orig_val) &&
+			(abituguru_write(data,
+			ABIT_UGURU_SENSOR_BANK2 + 2, attr->index,
+			data->bank2_settings[attr->index], 2) < 1)) {
+		data->bank2_settings[attr->index][0] = orig_val;
+		ret = -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* Fan PWM (speed control) */
+static ssize_t show_pwm_setting(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] *
+		abituguru_pwm_settings_multiplier[attr->nr]);
+}
+
+static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	u8 min;
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = count;
+	val = (val + abituguru_pwm_settings_multiplier[attr->nr] / 2) /
+				abituguru_pwm_settings_multiplier[attr->nr];
+
+	/* special case pwm1 min pwm% */
+	if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2)))
+		min = 77;
+	else
+		min = abituguru_pwm_min[attr->nr];
+
+	/* this check can be done before taking the lock */
+	if (val < min || val > abituguru_pwm_max[attr->nr])
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	/* this check needs to be done after taking the lock */
+	if ((attr->nr & 1) &&
+			(val >= data->pwm_settings[attr->index][attr->nr + 1]))
+		ret = -EINVAL;
+	else if (!(attr->nr & 1) &&
+			(val <= data->pwm_settings[attr->index][attr->nr - 1]))
+		ret = -EINVAL;
+	else if (data->pwm_settings[attr->index][attr->nr] != val) {
+		u8 orig_val = data->pwm_settings[attr->index][attr->nr];
+		data->pwm_settings[attr->index][attr->nr] = val;
+		if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+				attr->index, data->pwm_settings[attr->index],
+				5) <= attr->nr) {
+			data->pwm_settings[attr->index][attr->nr] =
+				orig_val;
+			ret = -EIO;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_pwm_sensor(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	int i;
+	/*
+	 * We need to walk to the temp sensor addresses to find what
+	 * the userspace id of the configured temp sensor is.
+	 */
+	for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++)
+		if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] ==
+				(data->pwm_settings[attr->index][0] & 0x0F))
+			return sprintf(buf, "%d\n", i+1);
+
+	return -ENXIO;
+}
+
+static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	ssize_t ret;
+	unsigned long val;
+	u8 orig_val;
+	u8 address;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val == 0 || val > data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR])
+		return -EINVAL;
+
+	val -= 1;
+	ret = count;
+	mutex_lock(&data->update_lock);
+	orig_val = data->pwm_settings[attr->index][0];
+	address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
+	data->pwm_settings[attr->index][0] &= 0xF0;
+	data->pwm_settings[attr->index][0] |= address;
+	if (data->pwm_settings[attr->index][0] != orig_val) {
+		if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, attr->index,
+				    data->pwm_settings[attr->index], 5) < 1) {
+			data->pwm_settings[attr->index][0] = orig_val;
+			ret = -EIO;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	int res = 0;
+	if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE)
+		res = 2;
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	u8 orig_val;
+	ssize_t ret;
+	unsigned long user_val;
+
+	ret = kstrtoul(buf, 10, &user_val);
+	if (ret)
+		return ret;
+
+	ret = count;
+	mutex_lock(&data->update_lock);
+	orig_val = data->pwm_settings[attr->index][0];
+	switch (user_val) {
+	case 0:
+		data->pwm_settings[attr->index][0] &=
+			~ABIT_UGURU_FAN_PWM_ENABLE;
+		break;
+	case 2:
+		data->pwm_settings[attr->index][0] |= ABIT_UGURU_FAN_PWM_ENABLE;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if ((data->pwm_settings[attr->index][0] != orig_val) &&
+			(abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+			attr->index, data->pwm_settings[attr->index],
+			5) < 1)) {
+		data->pwm_settings[attr->index][0] = orig_val;
+		ret = -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_name(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", ABIT_UGURU_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = {
+	{
+	SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0),
+	SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting,
+		store_bank1_setting, 1, 0),
+	SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL,
+		ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting,
+		store_bank1_setting, 2, 0),
+	SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL,
+		ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0),
+	}, {
+	SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0),
+	SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL,
+		ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting,
+		store_bank1_setting, 1, 0),
+	SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting,
+		store_bank1_setting, 2, 0),
+	SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask,
+		store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0),
+	}
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = {
+	SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting,
+		store_bank2_setting, 1, 0),
+	SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask,
+		store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask,
+		store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask,
+		store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0),
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = {
+	SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable,
+		store_pwm_enable, 0, 0),
+	SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor,
+		store_pwm_sensor, 0, 0),
+	SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting,
+		store_pwm_setting, 1, 0),
+	SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting,
+		store_pwm_setting, 2, 0),
+	SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting,
+		store_pwm_setting, 3, 0),
+	SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting,
+		store_pwm_setting, 4, 0),
+};
+
+static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
+	SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int abituguru_probe(struct platform_device *pdev)
+{
+	struct abituguru_data *data;
+	int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+	char *sysfs_filename;
+
+	/*
+	 * El weirdo probe order, to keep the sysfs order identical to the
+	 * BIOS and window-appliction listing order.
+	 */
+	const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = {
+		0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
+		0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	/* See if the uGuru is ready */
+	if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT)
+		data->uguru_ready = 1;
+
+	/*
+	 * Completely read the uGuru this has 2 purposes:
+	 * - testread / see if one really is there.
+	 * - make an in memory copy of all the uguru settings for future use.
+	 */
+	if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+			data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3)
+		goto abituguru_probe_error;
+
+	for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i,
+				&data->bank1_value[i], 1,
+				ABIT_UGURU_MAX_RETRIES) != 1)
+			goto abituguru_probe_error;
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i,
+				data->bank1_settings[i], 3,
+				ABIT_UGURU_MAX_RETRIES) != 3)
+			goto abituguru_probe_error;
+	}
+	/*
+	 * Note: We don't know how many bank2 sensors / pwms there really are,
+	 * but in order to "detect" this we need to read the maximum amount
+	 * anyways. If we read sensors/pwms not there we'll just read crap
+	 * this can't hurt. We need the detection because we don't want
+	 * unwanted writes, which will hurt!
+	 */
+	for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
+				&data->bank2_value[i], 1,
+				ABIT_UGURU_MAX_RETRIES) != 1)
+			goto abituguru_probe_error;
+		if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i,
+				data->bank2_settings[i], 2,
+				ABIT_UGURU_MAX_RETRIES) != 2)
+			goto abituguru_probe_error;
+	}
+	for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+		if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i,
+				data->pwm_settings[i], 5,
+				ABIT_UGURU_MAX_RETRIES) != 5)
+			goto abituguru_probe_error;
+	}
+	data->last_updated = jiffies;
+
+	/* Detect sensor types and fill the sysfs attr for bank1 */
+	sysfs_attr_i = 0;
+	sysfs_filename = data->sysfs_names;
+	sysfs_names_free = ABITUGURU_SYSFS_NAMES_LENGTH;
+	for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+		res = abituguru_detect_bank1_sensor_type(data, probe_order[i]);
+		if (res < 0)
+			goto abituguru_probe_error;
+		if (res == ABIT_UGURU_NC)
+			continue;
+
+		/* res 1 (temp) sensors have 7 sysfs entries, 0 (in) 9 */
+		for (j = 0; j < (res ? 7 : 9); j++) {
+			used = snprintf(sysfs_filename, sysfs_names_free,
+				abituguru_sysfs_bank1_templ[res][j].dev_attr.
+				attr.name, data->bank1_sensors[res] + res)
+				+ 1;
+			data->sysfs_attr[sysfs_attr_i] =
+				abituguru_sysfs_bank1_templ[res][j];
+			data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+				sysfs_filename;
+			data->sysfs_attr[sysfs_attr_i].index = probe_order[i];
+			sysfs_filename += used;
+			sysfs_names_free -= used;
+			sysfs_attr_i++;
+		}
+		data->bank1_max_value[probe_order[i]] =
+			abituguru_bank1_max_value[res];
+		data->bank1_address[res][data->bank1_sensors[res]] =
+			probe_order[i];
+		data->bank1_sensors[res]++;
+	}
+	/* Detect number of sensors and fill the sysfs attr for bank2 (fans) */
+	abituguru_detect_no_bank2_sensors(data);
+	for (i = 0; i < data->bank2_sensors; i++) {
+		for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_fan_templ); j++) {
+			used = snprintf(sysfs_filename, sysfs_names_free,
+				abituguru_sysfs_fan_templ[j].dev_attr.attr.name,
+				i + 1) + 1;
+			data->sysfs_attr[sysfs_attr_i] =
+				abituguru_sysfs_fan_templ[j];
+			data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+				sysfs_filename;
+			data->sysfs_attr[sysfs_attr_i].index = i;
+			sysfs_filename += used;
+			sysfs_names_free -= used;
+			sysfs_attr_i++;
+		}
+	}
+	/* Detect number of sensors and fill the sysfs attr for pwms */
+	abituguru_detect_no_pwms(data);
+	for (i = 0; i < data->pwms; i++) {
+		for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_pwm_templ); j++) {
+			used = snprintf(sysfs_filename, sysfs_names_free,
+				abituguru_sysfs_pwm_templ[j].dev_attr.attr.name,
+				i + 1) + 1;
+			data->sysfs_attr[sysfs_attr_i] =
+				abituguru_sysfs_pwm_templ[j];
+			data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+				sysfs_filename;
+			data->sysfs_attr[sysfs_attr_i].index = i;
+			sysfs_filename += used;
+			sysfs_names_free -= used;
+			sysfs_attr_i++;
+		}
+	}
+	/* Fail safe check, this should never happen! */
+	if (sysfs_names_free < 0) {
+		pr_err("Fatal error ran out of space for sysfs attr names. %s %s",
+		       never_happen, report_this);
+		res = -ENAMETOOLONG;
+		goto abituguru_probe_error;
+	}
+	pr_info("found Abit uGuru\n");
+
+	/* Register sysfs hooks */
+	for (i = 0; i < sysfs_attr_i; i++) {
+		res = device_create_file(&pdev->dev,
+					 &data->sysfs_attr[i].dev_attr);
+		if (res)
+			goto abituguru_probe_error;
+	}
+	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) {
+		res = device_create_file(&pdev->dev,
+					 &abituguru_sysfs_attr[i].dev_attr);
+		if (res)
+			goto abituguru_probe_error;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (!IS_ERR(data->hwmon_dev))
+		return 0; /* success */
+
+	res = PTR_ERR(data->hwmon_dev);
+abituguru_probe_error:
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru_sysfs_attr[i].dev_attr);
+	return res;
+}
+
+static int abituguru_remove(struct platform_device *pdev)
+{
+	int i;
+	struct abituguru_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru_sysfs_attr[i].dev_attr);
+
+	return 0;
+}
+
+static struct abituguru_data *abituguru_update_device(struct device *dev)
+{
+	int i, err;
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	/* fake a complete successful read if no update necessary. */
+	char success = 1;
+
+	mutex_lock(&data->update_lock);
+	if (time_after(jiffies, data->last_updated + HZ)) {
+		success = 0;
+		err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+				     data->alarms, 3, 0);
+		if (err != 3)
+			goto LEAVE_UPDATE;
+		for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+			err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1,
+					     i, &data->bank1_value[i], 1, 0);
+			if (err != 1)
+				goto LEAVE_UPDATE;
+			err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+					     i, data->bank1_settings[i], 3, 0);
+			if (err != 3)
+				goto LEAVE_UPDATE;
+		}
+		for (i = 0; i < data->bank2_sensors; i++) {
+			err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
+					     &data->bank2_value[i], 1, 0);
+			if (err != 1)
+				goto LEAVE_UPDATE;
+		}
+		/* success! */
+		success = 1;
+		data->update_timeouts = 0;
+LEAVE_UPDATE:
+		/* handle timeout condition */
+		if (!success && (err == -EBUSY || err >= 0)) {
+			/* No overflow please */
+			if (data->update_timeouts < 255u)
+				data->update_timeouts++;
+			if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) {
+				ABIT_UGURU_DEBUG(3, "timeout exceeded, will "
+					"try again next update\n");
+				/* Just a timeout, fake a successful read */
+				success = 1;
+			} else
+				ABIT_UGURU_DEBUG(1, "timeout exceeded %d "
+					"times waiting for more input state\n",
+					(int)data->update_timeouts);
+		}
+		/* On success set last_updated */
+		if (success)
+			data->last_updated = jiffies;
+	}
+	mutex_unlock(&data->update_lock);
+
+	if (success)
+		return data;
+	else
+		return NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int abituguru_suspend(struct device *dev)
+{
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	/*
+	 * make sure all communications with the uguru are done and no new
+	 * ones are started
+	 */
+	mutex_lock(&data->update_lock);
+	return 0;
+}
+
+static int abituguru_resume(struct device *dev)
+{
+	struct abituguru_data *data = dev_get_drvdata(dev);
+	/* See if the uGuru is still ready */
+	if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT)
+		data->uguru_ready = 0;
+	mutex_unlock(&data->update_lock);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
+#define ABIT_UGURU_PM	(&abituguru_pm)
+#else
+#define ABIT_UGURU_PM	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru_driver = {
+	.driver = {
+		.name	= ABIT_UGURU_NAME,
+		.pm	= ABIT_UGURU_PM,
+	},
+	.probe		= abituguru_probe,
+	.remove		= abituguru_remove,
+};
+
+static int __init abituguru_detect(void)
+{
+	/*
+	 * See if there is an uguru there. After a reboot uGuru will hold 0x00
+	 * at DATA and 0xAC, when this driver has already been loaded once
+	 * DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
+	 * scenario but some will hold 0x00.
+	 * Some uGuru's initially hold 0x09 at DATA and will only hold 0x08
+	 * after reading CMD first, so CMD must be read first!
+	 */
+	u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD);
+	u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA);
+	if (((data_val == 0x00) || (data_val == 0x08)) &&
+	    ((cmd_val == 0x00) || (cmd_val == 0xAC)))
+		return ABIT_UGURU_BASE;
+
+	ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = "
+		"0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+	if (force) {
+		pr_info("Assuming Abit uGuru is present because of \"force\" parameter\n");
+		return ABIT_UGURU_BASE;
+	}
+
+	/* No uGuru found */
+	return -ENODEV;
+}
+
+static struct platform_device *abituguru_pdev;
+
+static int __init abituguru_init(void)
+{
+	int address, err;
+	struct resource res = { .flags = IORESOURCE_IO };
+	const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+	/* safety check, refuse to load on non Abit motherboards */
+	if (!force && (!board_vendor ||
+			strcmp(board_vendor, "http://www.abit.com.tw/")))
+		return -ENODEV;
+
+	address = abituguru_detect();
+	if (address < 0)
+		return address;
+
+	err = platform_driver_register(&abituguru_driver);
+	if (err)
+		goto exit;
+
+	abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
+	if (!abituguru_pdev) {
+		pr_err("Device allocation failed\n");
+		err = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	res.start = address;
+	res.end = address + ABIT_UGURU_REGION_LENGTH - 1;
+	res.name = ABIT_UGURU_NAME;
+
+	err = platform_device_add_resources(abituguru_pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(abituguru_pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(abituguru_pdev);
+exit_driver_unregister:
+	platform_driver_unregister(&abituguru_driver);
+exit:
+	return err;
+}
+
+static void __exit abituguru_exit(void)
+{
+	platform_device_unregister(abituguru_pdev);
+	platform_driver_unregister(&abituguru_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Abit uGuru Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru_init);
+module_exit(abituguru_exit);
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
new file mode 100644
index 0000000..3d2a4ae
--- /dev/null
+++ b/drivers/hwmon/abituguru3.c
@@ -0,0 +1,1321 @@
+/*
+ * abituguru3.c
+ *
+ * Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
+ *
+ * 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.
+ */
+/*
+ * This driver supports the sensor part of revision 3 of the custom Abit uGuru
+ * chip found on newer Abit uGuru motherboards. Note: because of lack of specs
+ * only reading the sensors and their settings is supported.
+ */
+
+#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/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+
+/* uGuru3 bank addresses */
+#define ABIT_UGURU3_SETTINGS_BANK		0x01
+#define ABIT_UGURU3_SENSORS_BANK		0x08
+#define ABIT_UGURU3_MISC_BANK			0x09
+#define ABIT_UGURU3_ALARMS_START		0x1E
+#define ABIT_UGURU3_SETTINGS_START		0x24
+#define ABIT_UGURU3_VALUES_START		0x80
+#define ABIT_UGURU3_BOARD_ID			0x0A
+/* uGuru3 sensor bank flags */			     /* Alarm if: */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE	0x01 /*  temp over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE	0x02 /*  volt over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE	0x04 /*  volt under min */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG	0x10 /* temp is over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG	0x20 /* volt is over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG		0x40 /* volt is under min */
+#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE	0x01 /*   fan under min */
+#define ABIT_UGURU3_BEEP_ENABLE			0x08 /* beep if alarm */
+#define ABIT_UGURU3_SHUTDOWN_ENABLE		0x80 /* shutdown if alarm */
+/* sensor types */
+#define ABIT_UGURU3_IN_SENSOR			0
+#define ABIT_UGURU3_TEMP_SENSOR			1
+#define ABIT_UGURU3_FAN_SENSOR			2
+
+/*
+ * Timeouts / Retries, if these turn out to need a lot of fiddling we could
+ * convert them to params. Determined by trial and error. I assume this is
+ * cpu-speed independent, since the ISA-bus and not the CPU should be the
+ * bottleneck.
+ */
+#define ABIT_UGURU3_WAIT_TIMEOUT		250
+/*
+ * Normally the 0xAC at the end of synchronize() is reported after the
+ * first read, but sometimes not and we need to poll
+ */
+#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT		5
+/* utility macros */
+#define ABIT_UGURU3_NAME			"abituguru3"
+#define ABIT_UGURU3_DEBUG(format, arg...)		\
+	do {						\
+		if (verbose)				\
+			pr_debug(format , ## arg);	\
+	} while (0)
+
+/* Macros to help calculate the sysfs_names array length */
+#define ABIT_UGURU3_MAX_NO_SENSORS 26
+/*
+ * sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+ * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0
+ */
+#define ABIT_UGURU3_IN_NAMES_LENGTH \
+				(11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
+/*
+ * sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
+ * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
+ * temp??_label\0
+ */
+#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
+/*
+ * sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
+ * fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0
+ */
+#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
+/*
+ * Worst case scenario 16 in sensors (longest names_length) and the rest
+ * temp sensors (second longest names_length).
+ */
+#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
+	(ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
+
+/*
+ * All the macros below are named identical to the openguru2 program
+ * reverse engineered by Louis Kruger, hence the names might not be 100%
+ * logical. I could come up with better names, but I prefer keeping the names
+ * identical so that this driver can be compared with his work more easily.
+ */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU3_BASE			0x00E0
+#define ABIT_UGURU3_CMD				0x00
+#define ABIT_UGURU3_DATA			0x04
+#define ABIT_UGURU3_REGION_LENGTH		5
+/*
+ * The wait_xxx functions return this on success and the last contents
+ * of the DATA register (0-255) on failure.
+ */
+#define ABIT_UGURU3_SUCCESS			-1
+/* uGuru status flags */
+#define ABIT_UGURU3_STATUS_READY_FOR_READ	0x01
+#define ABIT_UGURU3_STATUS_BUSY			0x02
+
+
+/* Structures */
+struct abituguru3_sensor_info {
+	const char *name;
+	int port;
+	int type;
+	int multiplier;
+	int divisor;
+	int offset;
+};
+
+/* Avoid use of flexible array members */
+#define ABIT_UGURU3_MAX_DMI_NAMES 2
+
+struct abituguru3_motherboard_info {
+	u16 id;
+	const char *dmi_name[ABIT_UGURU3_MAX_DMI_NAMES + 1];
+	/* + 1 -> end of sensors indicated by a sensor with name == NULL */
+	struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
+};
+
+/*
+ * For the Abit uGuru, we need to keep some data in memory.
+ * The structure is dynamically allocated, at the same time when a new
+ * abituguru3 device is allocated.
+ */
+struct abituguru3_data {
+	struct device *hwmon_dev;	/* hwmon registered device */
+	struct mutex update_lock;	/* protect access to data and uGuru */
+	unsigned short addr;		/* uguru base address */
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/*
+	 * For convenience the sysfs attr and their names are generated
+	 * automatically. We have max 10 entries per sensor (for in sensors)
+	 */
+	struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
+		* 10];
+
+	/* Buffer to store the dynamically generated sysfs names */
+	char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
+
+	/* Pointer to the sensors info for the detected motherboard */
+	const struct abituguru3_sensor_info *sensors;
+
+	/*
+	 * The abituguru3 supports up to 48 sensors, and thus has registers
+	 * sets for 48 sensors, for convenience reasons / simplicity of the
+	 * code we always read and store all registers for all 48 sensors
+	 */
+
+	/* Alarms for all 48 sensors (1 bit per sensor) */
+	u8 alarms[48/8];
+
+	/* Value of all 48 sensors */
+	u8 value[48];
+
+	/*
+	 * Settings of all 48 sensors, note in and temp sensors (the first 32
+	 * sensors) have 3 bytes of settings, while fans only have 2 bytes,
+	 * for convenience we use 3 bytes for all sensors
+	 */
+	u8 settings[48][3];
+};
+
+
+/* Constants */
+static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
+	{ 0x000C, { NULL } /* Unknown, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000D, { NULL } /* Abit AW8, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "AUX4 Fan",		38, 2, 60, 1, 0 },
+		{ "AUX5 Fan",		39, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000E, { NULL } /* AL-8, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000F, { NULL } /* Unknown, need DMI string */, {
+
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0010, { NULL } /* Abit NI8 SLI GR, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "NB 1.4V",		 4, 0, 10, 1, 0 },
+		{ "SB 1.5V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "OTES1 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0011, { "AT8 32X", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 6, 0, 20, 1, 0 },
+		{ "NB 1.8V",		 4, 0, 10, 1, 0 },
+		{ "NB 1.8V Dual",	 5, 0, 10, 1, 0 },
+		{ "HTV 1.2",		 3, 0, 10, 1, 0 },
+		{ "PCIE 1.2V",		12, 0, 10, 1, 0 },
+		{ "NB 1.2V",		13, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "NB",			25, 1, 1, 1, 0 },
+		{ "System",		26, 1, 1, 1, 0 },
+		{ "PWM",		27, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0012, { NULL } /* Abit AN8 32X, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 5, 0, 20, 1, 0 },
+		{ "NB",			 4, 0, 10, 1, 0 },
+		{ "SB",			 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0013, { NULL } /* Abit AW8D, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "AUX4 Fan",		38, 2, 60, 1, 0 },
+		{ "AUX5 Fan",		39, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0014, { "AB9", "AB9 Pro", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0015, { NULL } /* Unknown, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 5, 0, 20, 1, 0 },
+		{ "NB",			 4, 0, 10, 1, 0 },
+		{ "SB",			 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0016, { "AW9D-MAX", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "OTES1 Fan",		38, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0017, { NULL } /* Unknown, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 6, 0, 20, 1, 0 },
+		{ "NB 1.8V",		 4, 0, 10, 1, 0 },
+		{ "NB 1.2V ",		13, 0, 10, 1, 0 },
+		{ "SB 1.2V",		 5, 0, 10, 1, 0 },
+		{ "PCIE 1.2V",		12, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "ATX +3.3V",		10, 0, 20, 1, 0 },
+		{ "ATX 5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		26, 1, 1, 1, 0 },
+		{ "PWM",		27, 1, 1, 1, 0 },
+		{ "CPU FAN",		32, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 FAN",		35, 2, 60, 1, 0 },
+		{ "AUX2 FAN",		36, 2, 60, 1, 0 },
+		{ "AUX3 FAN",		37, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0018, { "AB9 QuadGT", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0019, { "IN9 32X MAX", NULL }, {
+		{ "CPU Core",		 7, 0, 10, 1, 0 },
+		{ "DDR2",		13, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		14, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 20, 1, 0 },
+		{ "NB 1.2V",		 4, 0, 10, 1, 0 },
+		{ "SB 1.5V",		 6, 0, 10, 1, 0 },
+		{ "HyperTransport",	 5, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	12, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "ATX +3.3V",		10, 0, 20, 1, 0 },
+		{ "ATX 5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU FAN",		32, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 FAN",		33, 2, 60, 1, 0 },
+		{ "AUX2 FAN",		35, 2, 60, 1, 0 },
+		{ "AUX3 FAN",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x001A, { "IP35 Pro", "IP35 Pro XE", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX4 Fan",		37, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x001B, { NULL } /* Unknown, need DMI string */, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR3",		 1, 0, 20, 1, 0 },
+		{ "DDR3 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x001C, { "IX38 QuadGT", NULL }, {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0000, { NULL }, { { NULL, 0, 0, 0, 0, 0 } } }
+};
+
+
+/* Insmod parameters */
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+/* Default verbose is 1, since this driver is still in the testing phase */
+static bool verbose = 1;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+	"Please report this to the abituguru3 maintainer (see MAINTAINERS)";
+
+/* wait while the uguru is busy (usually after a write) */
+static int abituguru3_wait_while_busy(struct abituguru3_data *data)
+{
+	u8 x;
+	int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+	while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+			ABIT_UGURU3_STATUS_BUSY) {
+		timeout--;
+		if (timeout == 0)
+			return x;
+		/*
+		 * sleep a bit before our last try, to give the uGuru3 one
+		 * last chance to respond.
+		 */
+		if (timeout == 1)
+			msleep(1);
+	}
+	return ABIT_UGURU3_SUCCESS;
+}
+
+/* wait till uguru is ready to be read */
+static int abituguru3_wait_for_read(struct abituguru3_data *data)
+{
+	u8 x;
+	int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+	while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+			ABIT_UGURU3_STATUS_READY_FOR_READ)) {
+		timeout--;
+		if (timeout == 0)
+			return x;
+		/*
+		 * sleep a bit before our last try, to give the uGuru3 one
+		 * last chance to respond.
+		 */
+		if (timeout == 1)
+			msleep(1);
+	}
+	return ABIT_UGURU3_SUCCESS;
+}
+
+/*
+ * This synchronizes us with the uGuru3's protocol state machine, this
+ * must be done before each command.
+ */
+static int abituguru3_synchronize(struct abituguru3_data *data)
+{
+	int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
+
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
+			"wait, status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x20, data->addr + ABIT_UGURU3_DATA);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x10, data->addr + ABIT_UGURU3_CMD);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x00, data->addr + ABIT_UGURU3_CMD);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	x = abituguru3_wait_for_read(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
+		timeout--;
+		if (timeout == 0) {
+			ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
+				"hold 0xAC after synchronize, cmd: 0x%02x\n",
+				x);
+			return -EIO;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+/*
+ * Read count bytes from sensor sensor_addr in bank bank_addr and store the
+ * result in buf
+ */
+static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
+	u8 count, u8 *buf)
+{
+	int i, x;
+
+	x = abituguru3_synchronize(data);
+	if (x)
+		return x;
+
+	outb(0x1A, data->addr + ABIT_UGURU3_DATA);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
+			(unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(bank, data->addr + ABIT_UGURU3_CMD);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the bank, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(offset, data->addr + ABIT_UGURU3_CMD);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the offset, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(count, data->addr + ABIT_UGURU3_CMD);
+	x = abituguru3_wait_while_busy(data);
+	if (x != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the count, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		x = abituguru3_wait_for_read(data);
+		if (x != ABIT_UGURU3_SUCCESS) {
+			ABIT_UGURU3_DEBUG("timeout reading byte %d from "
+				"0x%02x:0x%02x, status: 0x%02x\n", i,
+				(unsigned int)bank, (unsigned int)offset, x);
+			break;
+		}
+		buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
+	}
+	return i;
+}
+
+/*
+ * Sensor settings are stored 1 byte per offset with the bytes
+ * placed add consecutive offsets.
+ */
+static int abituguru3_read_increment_offset(struct abituguru3_data *data,
+					    u8 bank, u8 offset, u8 count,
+					    u8 *buf, int offset_count)
+{
+	int i, x;
+
+	for (i = 0; i < offset_count; i++) {
+		x = abituguru3_read(data, bank, offset + i, count,
+				    buf + i * count);
+		if (x != count) {
+			if (x < 0)
+				return x;
+			return i * count + x;
+		}
+	}
+
+	return i * count;
+}
+
+/*
+ * Following are the sysfs callback functions. These functions expect:
+ * sensor_device_attribute_2->index:   index into the data->sensors array
+ * sensor_device_attribute_2->nr:      register offset, bitmask or NA.
+ */
+static struct abituguru3_data *abituguru3_update_device(struct device *dev);
+
+static ssize_t show_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int value;
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = abituguru3_update_device(dev);
+	const struct abituguru3_sensor_info *sensor;
+
+	if (!data)
+		return -EIO;
+
+	sensor = &data->sensors[attr->index];
+
+	/* are we reading a setting, or is this a normal read? */
+	if (attr->nr)
+		value = data->settings[sensor->port][attr->nr];
+	else
+		value = data->value[sensor->port];
+
+	/* convert the value */
+	value = (value * sensor->multiplier) / sensor->divisor +
+		sensor->offset;
+
+	/*
+	 * alternatively we could update the sensors settings struct for this,
+	 * but then its contents would differ from the windows sw ini files
+	 */
+	if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
+		value *= 1000;
+
+	return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int port;
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = abituguru3_update_device(dev);
+
+	if (!data)
+		return -EIO;
+
+	port = data->sensors[attr->index].port;
+
+	/*
+	 * See if the alarm bit for this sensor is set and if a bitmask is
+	 * given in attr->nr also check if the alarm matches the type of alarm
+	 * we're looking for (for volt it can be either low or high). The type
+	 * is stored in a few readonly bits in the settings of the sensor.
+	 */
+	if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
+			(!attr->nr || (data->settings[port][0] & attr->nr)))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_mask(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_label(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->sensors[attr->index].name);
+}
+
+static ssize_t show_name(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
+	SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
+	SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
+		ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
+		ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
+	}, {
+	SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
+	SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
+	}, {
+	SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
+} };
+
+static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
+	SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int abituguru3_probe(struct platform_device *pdev)
+{
+	const int no_sysfs_attr[3] = { 10, 8, 7 };
+	int sensor_index[3] = { 0, 1, 1 };
+	struct abituguru3_data *data;
+	int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+	char *sysfs_filename;
+	u8 buf[2];
+	u16 id;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	/* Read the motherboard ID */
+	i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK, ABIT_UGURU3_BOARD_ID,
+			    2, buf);
+	if (i != 2)
+		goto abituguru3_probe_error;
+
+	/* Completely read the uGuru to see if one really is there */
+	if (!abituguru3_update_device(&pdev->dev))
+		goto abituguru3_probe_error;
+
+	/* lookup the ID in our motherboard table */
+	id = ((u16)buf[0] << 8) | (u16)buf[1];
+	for (i = 0; abituguru3_motherboards[i].id; i++)
+		if (abituguru3_motherboards[i].id == id)
+			break;
+	if (!abituguru3_motherboards[i].id) {
+		pr_err("error unknown motherboard ID: %04X. %s\n",
+		       (unsigned int)id, report_this);
+		goto abituguru3_probe_error;
+	}
+	data->sensors = abituguru3_motherboards[i].sensors;
+
+	pr_info("found Abit uGuru3, motherboard ID: %04X\n", (unsigned int)id);
+
+	/* Fill the sysfs attr array */
+	sysfs_attr_i = 0;
+	sysfs_filename = data->sysfs_names;
+	sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
+	for (i = 0; data->sensors[i].name; i++) {
+		/* Fail safe check, this should never happen! */
+		if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
+			pr_err("Fatal error motherboard has more sensors then ABIT_UGURU3_MAX_NO_SENSORS. %s %s\n",
+			       never_happen, report_this);
+			res = -ENAMETOOLONG;
+			goto abituguru3_probe_error;
+		}
+		type = data->sensors[i].type;
+		for (j = 0; j < no_sysfs_attr[type]; j++) {
+			used = snprintf(sysfs_filename, sysfs_names_free,
+				abituguru3_sysfs_templ[type][j].dev_attr.attr.
+				name, sensor_index[type]) + 1;
+			data->sysfs_attr[sysfs_attr_i] =
+				abituguru3_sysfs_templ[type][j];
+			data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+				sysfs_filename;
+			data->sysfs_attr[sysfs_attr_i].index = i;
+			sysfs_filename += used;
+			sysfs_names_free -= used;
+			sysfs_attr_i++;
+		}
+		sensor_index[type]++;
+	}
+	/* Fail safe check, this should never happen! */
+	if (sysfs_names_free < 0) {
+		pr_err("Fatal error ran out of space for sysfs attr names. %s %s\n",
+		       never_happen, report_this);
+		res = -ENAMETOOLONG;
+		goto abituguru3_probe_error;
+	}
+
+	/* Register sysfs hooks */
+	for (i = 0; i < sysfs_attr_i; i++)
+		if (device_create_file(&pdev->dev,
+				&data->sysfs_attr[i].dev_attr))
+			goto abituguru3_probe_error;
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		if (device_create_file(&pdev->dev,
+				&abituguru3_sysfs_attr[i].dev_attr))
+			goto abituguru3_probe_error;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		res = PTR_ERR(data->hwmon_dev);
+		goto abituguru3_probe_error;
+	}
+
+	return 0; /* success */
+
+abituguru3_probe_error:
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru3_sysfs_attr[i].dev_attr);
+	return res;
+}
+
+static int abituguru3_remove(struct platform_device *pdev)
+{
+	int i;
+	struct abituguru3_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru3_sysfs_attr[i].dev_attr);
+	return 0;
+}
+
+static struct abituguru3_data *abituguru3_update_device(struct device *dev)
+{
+	int i;
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->update_lock);
+	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+		/* Clear data->valid while updating */
+		data->valid = 0;
+		/* Read alarms */
+		if (abituguru3_read_increment_offset(data,
+				ABIT_UGURU3_SETTINGS_BANK,
+				ABIT_UGURU3_ALARMS_START,
+				1, data->alarms, 48/8) != (48/8))
+			goto LEAVE_UPDATE;
+		/* Read in and temp sensors (3 byte settings / sensor) */
+		for (i = 0; i < 32; i++) {
+			if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+					ABIT_UGURU3_VALUES_START + i,
+					1, &data->value[i]) != 1)
+				goto LEAVE_UPDATE;
+			if (abituguru3_read_increment_offset(data,
+					ABIT_UGURU3_SETTINGS_BANK,
+					ABIT_UGURU3_SETTINGS_START + i * 3,
+					1,
+					data->settings[i], 3) != 3)
+				goto LEAVE_UPDATE;
+		}
+		/* Read temp sensors (2 byte settings / sensor) */
+		for (i = 0; i < 16; i++) {
+			if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+					ABIT_UGURU3_VALUES_START + 32 + i,
+					1, &data->value[32 + i]) != 1)
+				goto LEAVE_UPDATE;
+			if (abituguru3_read_increment_offset(data,
+					ABIT_UGURU3_SETTINGS_BANK,
+					ABIT_UGURU3_SETTINGS_START + 32 * 3 +
+						i * 2, 1,
+					data->settings[32 + i], 2) != 2)
+				goto LEAVE_UPDATE;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+LEAVE_UPDATE:
+	mutex_unlock(&data->update_lock);
+	if (data->valid)
+		return data;
+	else
+		return NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int abituguru3_suspend(struct device *dev)
+{
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+	/*
+	 * make sure all communications with the uguru3 are done and no new
+	 * ones are started
+	 */
+	mutex_lock(&data->update_lock);
+	return 0;
+}
+
+static int abituguru3_resume(struct device *dev)
+{
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+	mutex_unlock(&data->update_lock);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
+#define ABIT_UGURU3_PM	(&abituguru3_pm)
+#else
+#define ABIT_UGURU3_PM	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru3_driver = {
+	.driver = {
+		.name	= ABIT_UGURU3_NAME,
+		.pm	= ABIT_UGURU3_PM
+	},
+	.probe	= abituguru3_probe,
+	.remove	= abituguru3_remove,
+};
+
+static int __init abituguru3_dmi_detect(void)
+{
+	const char *board_vendor, *board_name;
+	int i, err = (force) ? 1 : -ENODEV;
+	const char *const *dmi_name;
+	size_t sublen;
+
+	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+	if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/"))
+		return err;
+
+	board_name = dmi_get_system_info(DMI_BOARD_NAME);
+	if (!board_name)
+		return err;
+
+	/*
+	 * At the moment, we don't care about the part of the vendor
+	 * DMI string contained in brackets. Truncate the string at
+	 * the first occurrence of a bracket. Trim any trailing space
+	 * from the substring.
+	 */
+	sublen = strcspn(board_name, "(");
+	while (sublen > 0 && board_name[sublen - 1] == ' ')
+		sublen--;
+
+	for (i = 0; abituguru3_motherboards[i].id; i++) {
+		dmi_name = abituguru3_motherboards[i].dmi_name;
+		for ( ; *dmi_name; dmi_name++) {
+			if (strlen(*dmi_name) != sublen)
+				continue;
+			if (!strncasecmp(board_name, *dmi_name, sublen))
+				return 0;
+		}
+	}
+
+	/* No match found */
+	return 1;
+}
+
+/*
+ * FIXME: Manual detection should die eventually; we need to collect stable
+ *        DMI model names first before we can rely entirely on CONFIG_DMI.
+ */
+
+static int __init abituguru3_detect(void)
+{
+	/*
+	 * See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
+	 * 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
+	 * or 0x55 at CMD instead, why is unknown.
+	 */
+	u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
+	u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
+	if (((data_val == 0x00) || (data_val == 0x08)) &&
+			((cmd_val == 0xAC) || (cmd_val == 0x05) ||
+			 (cmd_val == 0x55)))
+		return 0;
+
+	ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
+		"0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+	if (force) {
+		pr_info("Assuming Abit uGuru3 is present because of \"force\" parameter\n");
+		return 0;
+	}
+
+	/* No uGuru3 found */
+	return -ENODEV;
+}
+
+static struct platform_device *abituguru3_pdev;
+
+static int __init abituguru3_init(void)
+{
+	struct resource res = { .flags = IORESOURCE_IO };
+	int err;
+
+	/* Attempt DMI detection first */
+	err = abituguru3_dmi_detect();
+	if (err < 0)
+		return err;
+
+	/*
+	 * Fall back to manual detection if there was no exact
+	 * board name match, or force was specified.
+	 */
+	if (err > 0) {
+		err = abituguru3_detect();
+		if (err)
+			return err;
+
+		pr_warn("this motherboard was not detected using DMI. "
+			"Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
+	}
+
+	err = platform_driver_register(&abituguru3_driver);
+	if (err)
+		goto exit;
+
+	abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME,
+						ABIT_UGURU3_BASE);
+	if (!abituguru3_pdev) {
+		pr_err("Device allocation failed\n");
+		err = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	res.start = ABIT_UGURU3_BASE;
+	res.end = ABIT_UGURU3_BASE + ABIT_UGURU3_REGION_LENGTH - 1;
+	res.name = ABIT_UGURU3_NAME;
+
+	err = platform_device_add_resources(abituguru3_pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(abituguru3_pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(abituguru3_pdev);
+exit_driver_unregister:
+	platform_driver_unregister(&abituguru3_driver);
+exit:
+	return err;
+}
+
+static void __exit abituguru3_exit(void)
+{
+	platform_device_unregister(abituguru3_pdev);
+	platform_driver_unregister(&abituguru3_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru3_init);
+module_exit(abituguru3_exit);
diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c
new file mode 100644
index 0000000..d87cae8
--- /dev/null
+++ b/drivers/hwmon/abx500.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ *         Hongbo Zhang <hongbo.zhang@linaro.org>
+ * License Terms: GNU General Public License v2
+ *
+ * ABX500 does not provide auto ADC, so to monitor the required temperatures,
+ * a periodic work is used. It is more important to not wake up the CPU than
+ * to perform this job, hence the use of a deferred delay.
+ *
+ * A deferred delay for thermal monitor is considered safe because:
+ * If the chip gets too hot during a sleep state it's most likely due to
+ * external factors, such as the surrounding temperature. I.e. no SW decisions
+ * will make any difference.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include "abx500.h"
+
+#define DEFAULT_MONITOR_DELAY	HZ
+#define DEFAULT_MAX_TEMP	130
+
+static inline void schedule_monitor(struct abx500_temp *data)
+{
+	data->work_active = true;
+	schedule_delayed_work(&data->work, DEFAULT_MONITOR_DELAY);
+}
+
+static void threshold_updated(struct abx500_temp *data)
+{
+	int i;
+	for (i = 0; i < data->monitored_sensors; i++)
+		if (data->max[i] != 0 || data->min[i] != 0) {
+			schedule_monitor(data);
+			return;
+		}
+
+	dev_dbg(&data->pdev->dev, "No active thresholds.\n");
+	cancel_delayed_work_sync(&data->work);
+	data->work_active = false;
+}
+
+static void gpadc_monitor(struct work_struct *work)
+{
+	int temp, i, ret;
+	char alarm_node[30];
+	bool updated_min_alarm, updated_max_alarm;
+	struct abx500_temp *data;
+
+	data = container_of(work, struct abx500_temp, work.work);
+	mutex_lock(&data->lock);
+
+	for (i = 0; i < data->monitored_sensors; i++) {
+		/* Thresholds are considered inactive if set to 0 */
+		if (data->max[i] == 0 && data->min[i] == 0)
+			continue;
+
+		if (data->max[i] < data->min[i])
+			continue;
+
+		ret = data->ops.read_sensor(data, data->gpadc_addr[i], &temp);
+		if (ret < 0) {
+			dev_err(&data->pdev->dev, "GPADC read failed\n");
+			continue;
+		}
+
+		updated_min_alarm = false;
+		updated_max_alarm = false;
+
+		if (data->min[i] != 0) {
+			if (temp < data->min[i]) {
+				if (data->min_alarm[i] == false) {
+					data->min_alarm[i] = true;
+					updated_min_alarm = true;
+				}
+			} else {
+				if (data->min_alarm[i] == true) {
+					data->min_alarm[i] = false;
+					updated_min_alarm = true;
+				}
+			}
+		}
+		if (data->max[i] != 0) {
+			if (temp > data->max[i]) {
+				if (data->max_alarm[i] == false) {
+					data->max_alarm[i] = true;
+					updated_max_alarm = true;
+				}
+			} else if (temp < data->max[i] - data->max_hyst[i]) {
+				if (data->max_alarm[i] == true) {
+					data->max_alarm[i] = false;
+					updated_max_alarm = true;
+				}
+			}
+		}
+
+		if (updated_min_alarm) {
+			ret = sprintf(alarm_node, "temp%d_min_alarm", i + 1);
+			sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
+		}
+		if (updated_max_alarm) {
+			ret = sprintf(alarm_node, "temp%d_max_alarm", i + 1);
+			sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
+		}
+	}
+
+	schedule_monitor(data);
+	mutex_unlock(&data->lock);
+}
+
+/* HWMON sysfs interfaces */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	/* Show chip name */
+	return data->ops.show_name(dev, devattr, buf);
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	/* Show each sensor label */
+	return data->ops.show_label(dev, devattr, buf);
+}
+
+static ssize_t show_input(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	int ret, temp;
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	u8 gpadc_addr = data->gpadc_addr[attr->index];
+
+	ret = data->ops.read_sensor(data, gpadc_addr, &temp);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+/* Set functions (RW nodes) */
+static ssize_t set_min(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	unsigned long val;
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int res = kstrtol(buf, 10, &val);
+	if (res < 0)
+		return res;
+
+	val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+	mutex_lock(&data->lock);
+	data->min[attr->index] = val;
+	threshold_updated(data);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	unsigned long val;
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int res = kstrtol(buf, 10, &val);
+	if (res < 0)
+		return res;
+
+	val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+	mutex_lock(&data->lock);
+	data->max[attr->index] = val;
+	threshold_updated(data);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t set_max_hyst(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	unsigned long val;
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int res = kstrtoul(buf, 10, &val);
+	if (res < 0)
+		return res;
+
+	val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+	mutex_lock(&data->lock);
+	data->max_hyst[attr->index] = val;
+	threshold_updated(data);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+/* Show functions (RO nodes) */
+static ssize_t show_min(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%lu\n", data->min[attr->index]);
+}
+
+static ssize_t show_max(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%lu\n", data->max[attr->index]);
+}
+
+static ssize_t show_max_hyst(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%lu\n", data->max_hyst[attr->index]);
+}
+
+static ssize_t show_min_alarm(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%d\n", data->min_alarm[attr->index]);
+}
+
+static ssize_t show_max_alarm(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct abx500_temp *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%d\n", data->max_alarm[attr->index]);
+}
+
+static umode_t abx500_attrs_visible(struct kobject *kobj,
+				   struct attribute *attr, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct abx500_temp *data = dev_get_drvdata(dev);
+
+	if (data->ops.is_visible)
+		return data->ops.is_visible(attr, n);
+
+	return attr->mode;
+}
+
+/* Chip name, required by hwmon */
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+/* GPADC - SENSOR1 */
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_min, set_min, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  show_max_hyst, set_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_min_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_max_alarm, NULL, 0);
+
+/* GPADC - SENSOR2 */
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IWUSR | S_IRUGO,
+			  show_max_hyst, set_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_min_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_max_alarm, NULL, 1);
+
+/* GPADC - SENSOR3 */
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IWUSR | S_IRUGO,
+			  show_max_hyst, set_max_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_min_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_max_alarm, NULL, 2);
+
+/* GPADC - SENSOR4 */
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_min, set_min, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_max, set_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IWUSR | S_IRUGO,
+			  show_max_hyst, set_max_hyst, 3);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_min_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_max_alarm, NULL, 3);
+
+static struct attribute *abx500_temp_attributes[] = {
+	&sensor_dev_attr_name.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_label.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp4_label.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group abx500_temp_group = {
+	.attrs = abx500_temp_attributes,
+	.is_visible = abx500_attrs_visible,
+};
+
+static irqreturn_t abx500_temp_irq_handler(int irq, void *irq_data)
+{
+	struct platform_device *pdev = irq_data;
+	struct abx500_temp *data = platform_get_drvdata(pdev);
+
+	data->ops.irq_handler(irq, data);
+	return IRQ_HANDLED;
+}
+
+static int setup_irqs(struct platform_device *pdev)
+{
+	int ret;
+	int irq = platform_get_irq_byname(pdev, "ABX500_TEMP_WARM");
+
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Get irq by name failed\n");
+		return irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+		abx500_temp_irq_handler, 0, "abx500-temp", pdev);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int abx500_temp_probe(struct platform_device *pdev)
+{
+	struct abx500_temp *data;
+	int err;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->pdev = pdev;
+	mutex_init(&data->lock);
+
+	/* Chip specific initialization */
+	err = abx500_hwmon_init(data);
+	if (err	< 0 || !data->ops.read_sensor || !data->ops.show_name ||
+			!data->ops.show_label)
+		return err;
+
+	INIT_DEFERRABLE_WORK(&data->work, gpadc_monitor);
+
+	platform_set_drvdata(pdev, data);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &abx500_temp_group);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err);
+		return err;
+	}
+
+	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_sysfs_group;
+	}
+
+	if (data->ops.irq_handler) {
+		err = setup_irqs(pdev);
+		if (err < 0)
+			goto exit_hwmon_reg;
+	}
+	return 0;
+
+exit_hwmon_reg:
+	hwmon_device_unregister(data->hwmon_dev);
+exit_sysfs_group:
+	sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
+	return err;
+}
+
+static int abx500_temp_remove(struct platform_device *pdev)
+{
+	struct abx500_temp *data = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&data->work);
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
+
+	return 0;
+}
+
+static int abx500_temp_suspend(struct platform_device *pdev,
+			       pm_message_t state)
+{
+	struct abx500_temp *data = platform_get_drvdata(pdev);
+
+	if (data->work_active)
+		cancel_delayed_work_sync(&data->work);
+
+	return 0;
+}
+
+static int abx500_temp_resume(struct platform_device *pdev)
+{
+	struct abx500_temp *data = platform_get_drvdata(pdev);
+
+	if (data->work_active)
+		schedule_monitor(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id abx500_temp_match[] = {
+	{ .compatible = "stericsson,abx500-temp" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, abx500_temp_match);
+#endif
+
+static struct platform_driver abx500_temp_driver = {
+	.driver = {
+		.name = "abx500-temp",
+		.of_match_table = of_match_ptr(abx500_temp_match),
+	},
+	.suspend = abx500_temp_suspend,
+	.resume = abx500_temp_resume,
+	.probe = abx500_temp_probe,
+	.remove = abx500_temp_remove,
+};
+
+module_platform_driver(abx500_temp_driver);
+
+MODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>");
+MODULE_DESCRIPTION("ABX500 temperature driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/abx500.h b/drivers/hwmon/abx500.h
new file mode 100644
index 0000000..9b295e6
--- /dev/null
+++ b/drivers/hwmon/abx500.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * License terms: GNU General Public License v2
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ *         Hongbo Zhang <hongbo.zhang@linaro.com>
+ */
+
+#ifndef _ABX500_H
+#define _ABX500_H
+
+#define NUM_SENSORS 5
+
+struct abx500_temp;
+
+/*
+ * struct abx500_temp_ops - abx500 chip specific ops
+ * @read_sensor: reads gpadc output
+ * @irq_handler: irq handler
+ * @show_name: hwmon device name
+ * @show_label: hwmon attribute label
+ * @is_visible: is attribute visible
+ */
+struct abx500_temp_ops {
+	int (*read_sensor)(struct abx500_temp *, u8, int *);
+	int (*irq_handler)(int, struct abx500_temp *);
+	ssize_t (*show_name)(struct device *,
+			struct device_attribute *, char *);
+	ssize_t (*show_label) (struct device *,
+			struct device_attribute *, char *);
+	int (*is_visible)(struct attribute *, int);
+};
+
+/*
+ * struct abx500_temp - representation of temp mon device
+ * @pdev: platform device
+ * @hwmon_dev: hwmon device
+ * @ops: abx500 chip specific ops
+ * @gpadc_addr: gpadc channel address
+ * @min: sensor temperature min value
+ * @max: sensor temperature max value
+ * @max_hyst: sensor temperature hysteresis value for max limit
+ * @min_alarm: sensor temperature min alarm
+ * @max_alarm: sensor temperature max alarm
+ * @work: delayed work scheduled to monitor temperature periodically
+ * @work_active: True if work is active
+ * @lock: mutex
+ * @monitored_sensors: number of monitored sensors
+ * @plat_data: private usage, usually points to platform specific data
+ */
+struct abx500_temp {
+	struct platform_device *pdev;
+	struct device *hwmon_dev;
+	struct abx500_temp_ops ops;
+	u8 gpadc_addr[NUM_SENSORS];
+	unsigned long min[NUM_SENSORS];
+	unsigned long max[NUM_SENSORS];
+	unsigned long max_hyst[NUM_SENSORS];
+	bool min_alarm[NUM_SENSORS];
+	bool max_alarm[NUM_SENSORS];
+	struct delayed_work work;
+	bool work_active;
+	struct mutex lock;
+	int monitored_sensors;
+	void *plat_data;
+};
+
+int abx500_hwmon_init(struct abx500_temp *data);
+
+#endif /* _ABX500_H */
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
new file mode 100644
index 0000000..579bdf9
--- /dev/null
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -0,0 +1,1015 @@
+/*
+ * A hwmon driver for ACPI 4.0 power meters
+ * Copyright (C) 2009 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <linux/kdev_t.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/acpi.h>
+
+#define ACPI_POWER_METER_NAME		"power_meter"
+ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
+#define ACPI_POWER_METER_DEVICE_NAME	"Power Meter"
+#define ACPI_POWER_METER_CLASS		"pwr_meter_resource"
+
+#define NUM_SENSORS			17
+
+#define POWER_METER_CAN_MEASURE	(1 << 0)
+#define POWER_METER_CAN_TRIP	(1 << 1)
+#define POWER_METER_CAN_CAP	(1 << 2)
+#define POWER_METER_CAN_NOTIFY	(1 << 3)
+#define POWER_METER_IS_BATTERY	(1 << 8)
+#define UNKNOWN_HYSTERESIS	0xFFFFFFFF
+
+#define METER_NOTIFY_CONFIG	0x80
+#define METER_NOTIFY_TRIP	0x81
+#define METER_NOTIFY_CAP	0x82
+#define METER_NOTIFY_CAPPING	0x83
+#define METER_NOTIFY_INTERVAL	0x84
+
+#define POWER_AVERAGE_NAME	"power1_average"
+#define POWER_CAP_NAME		"power1_cap"
+#define POWER_AVG_INTERVAL_NAME	"power1_average_interval"
+#define POWER_ALARM_NAME	"power1_alarm"
+
+static int cap_in_hardware;
+static bool force_cap_on;
+
+static int can_cap_in_hardware(void)
+{
+	return force_cap_on || cap_in_hardware;
+}
+
+static const struct acpi_device_id power_meter_ids[] = {
+	{"ACPI000D", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, power_meter_ids);
+
+struct acpi_power_meter_capabilities {
+	u64		flags;
+	u64		units;
+	u64		type;
+	u64		accuracy;
+	u64		sampling_time;
+	u64		min_avg_interval;
+	u64		max_avg_interval;
+	u64		hysteresis;
+	u64		configurable_cap;
+	u64		min_cap;
+	u64		max_cap;
+};
+
+struct acpi_power_meter_resource {
+	struct acpi_device	*acpi_dev;
+	acpi_bus_id		name;
+	struct mutex		lock;
+	struct device		*hwmon_dev;
+	struct acpi_power_meter_capabilities	caps;
+	acpi_string		model_number;
+	acpi_string		serial_number;
+	acpi_string		oem_info;
+	u64		power;
+	u64		cap;
+	u64		avg_interval;
+	int			sensors_valid;
+	unsigned long		sensors_last_updated;
+	struct sensor_device_attribute	sensors[NUM_SENSORS];
+	int			num_sensors;
+	s64			trip[2];
+	int			num_domain_devices;
+	struct acpi_device	**domain_devices;
+	struct kobject		*holders_dir;
+};
+
+struct sensor_template {
+	char *label;
+	ssize_t (*show)(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf);
+	ssize_t (*set)(struct device *dev,
+		       struct device_attribute *devattr,
+		       const char *buf, size_t count);
+	int index;
+};
+
+/* Averaging interval */
+static int update_avg_interval(struct acpi_power_meter_resource *resource)
+{
+	unsigned long long data;
+	acpi_status status;
+
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI",
+				       NULL, &data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI"));
+		return -ENODEV;
+	}
+
+	resource->avg_interval = data;
+	return 0;
+}
+
+static ssize_t show_avg_interval(struct device *dev,
+				 struct device_attribute *devattr,
+				 char *buf)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+	mutex_lock(&resource->lock);
+	update_avg_interval(resource);
+	mutex_unlock(&resource->lock);
+
+	return sprintf(buf, "%llu\n", resource->avg_interval);
+}
+
+static ssize_t set_avg_interval(struct device *dev,
+				struct device_attribute *devattr,
+				const char *buf, size_t count)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+	struct acpi_object_list args = { 1, &arg0 };
+	int res;
+	unsigned long temp;
+	unsigned long long data;
+	acpi_status status;
+
+	res = kstrtoul(buf, 10, &temp);
+	if (res)
+		return res;
+
+	if (temp > resource->caps.max_avg_interval ||
+	    temp < resource->caps.min_avg_interval)
+		return -EINVAL;
+	arg0.integer.value = temp;
+
+	mutex_lock(&resource->lock);
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI",
+				       &args, &data);
+	if (!ACPI_FAILURE(status))
+		resource->avg_interval = temp;
+	mutex_unlock(&resource->lock);
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI"));
+		return -EINVAL;
+	}
+
+	/* _PAI returns 0 on success, nonzero otherwise */
+	if (data)
+		return -EINVAL;
+
+	return count;
+}
+
+/* Cap functions */
+static int update_cap(struct acpi_power_meter_resource *resource)
+{
+	unsigned long long data;
+	acpi_status status;
+
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL",
+				       NULL, &data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL"));
+		return -ENODEV;
+	}
+
+	resource->cap = data;
+	return 0;
+}
+
+static ssize_t show_cap(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+	mutex_lock(&resource->lock);
+	update_cap(resource);
+	mutex_unlock(&resource->lock);
+
+	return sprintf(buf, "%llu\n", resource->cap * 1000);
+}
+
+static ssize_t set_cap(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+	struct acpi_object_list args = { 1, &arg0 };
+	int res;
+	unsigned long temp;
+	unsigned long long data;
+	acpi_status status;
+
+	res = kstrtoul(buf, 10, &temp);
+	if (res)
+		return res;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+	if (temp > resource->caps.max_cap || temp < resource->caps.min_cap)
+		return -EINVAL;
+	arg0.integer.value = temp;
+
+	mutex_lock(&resource->lock);
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL",
+				       &args, &data);
+	if (!ACPI_FAILURE(status))
+		resource->cap = temp;
+	mutex_unlock(&resource->lock);
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL"));
+		return -EINVAL;
+	}
+
+	/* _SHL returns 0 on success, nonzero otherwise */
+	if (data)
+		return -EINVAL;
+
+	return count;
+}
+
+/* Power meter trip points */
+static int set_acpi_trip(struct acpi_power_meter_resource *resource)
+{
+	union acpi_object arg_objs[] = {
+		{ACPI_TYPE_INTEGER},
+		{ACPI_TYPE_INTEGER}
+	};
+	struct acpi_object_list args = { 2, arg_objs };
+	unsigned long long data;
+	acpi_status status;
+
+	/* Both trip levels must be set */
+	if (resource->trip[0] < 0 || resource->trip[1] < 0)
+		return 0;
+
+	/* This driver stores min, max; ACPI wants max, min. */
+	arg_objs[0].integer.value = resource->trip[1];
+	arg_objs[1].integer.value = resource->trip[0];
+
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP",
+				       &args, &data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP"));
+		return -EINVAL;
+	}
+
+	/* _PTP returns 0 on success, nonzero otherwise */
+	if (data)
+		return -EINVAL;
+
+	return 0;
+}
+
+static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	int res;
+	unsigned long temp;
+
+	res = kstrtoul(buf, 10, &temp);
+	if (res)
+		return res;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+
+	mutex_lock(&resource->lock);
+	resource->trip[attr->index - 7] = temp;
+	res = set_acpi_trip(resource);
+	mutex_unlock(&resource->lock);
+
+	if (res)
+		return res;
+
+	return count;
+}
+
+/* Power meter */
+static int update_meter(struct acpi_power_meter_resource *resource)
+{
+	unsigned long long data;
+	acpi_status status;
+	unsigned long local_jiffies = jiffies;
+
+	if (time_before(local_jiffies, resource->sensors_last_updated +
+			msecs_to_jiffies(resource->caps.sampling_time)) &&
+			resource->sensors_valid)
+		return 0;
+
+	status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
+				       NULL, &data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM"));
+		return -ENODEV;
+	}
+
+	resource->power = data;
+	resource->sensors_valid = 1;
+	resource->sensors_last_updated = jiffies;
+	return 0;
+}
+
+static ssize_t show_power(struct device *dev,
+			  struct device_attribute *devattr,
+			  char *buf)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+	mutex_lock(&resource->lock);
+	update_meter(resource);
+	mutex_unlock(&resource->lock);
+
+	return sprintf(buf, "%llu\n", resource->power * 1000);
+}
+
+/* Miscellaneous */
+static ssize_t show_str(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	acpi_string val;
+
+	switch (attr->index) {
+	case 0:
+		val = resource->model_number;
+		break;
+	case 1:
+		val = resource->serial_number;
+		break;
+	case 2:
+		val = resource->oem_info;
+		break;
+	default:
+		WARN(1, "Implementation error: unexpected attribute index %d\n",
+		     attr->index);
+		val = "";
+		break;
+	}
+
+	return sprintf(buf, "%s\n", val);
+}
+
+static ssize_t show_val(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	u64 val = 0;
+
+	switch (attr->index) {
+	case 0:
+		val = resource->caps.min_avg_interval;
+		break;
+	case 1:
+		val = resource->caps.max_avg_interval;
+		break;
+	case 2:
+		val = resource->caps.min_cap * 1000;
+		break;
+	case 3:
+		val = resource->caps.max_cap * 1000;
+		break;
+	case 4:
+		if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS)
+			return sprintf(buf, "unknown\n");
+
+		val = resource->caps.hysteresis * 1000;
+		break;
+	case 5:
+		if (resource->caps.flags & POWER_METER_IS_BATTERY)
+			val = 1;
+		else
+			val = 0;
+		break;
+	case 6:
+		if (resource->power > resource->cap)
+			val = 1;
+		else
+			val = 0;
+		break;
+	case 7:
+	case 8:
+		if (resource->trip[attr->index - 7] < 0)
+			return sprintf(buf, "unknown\n");
+
+		val = resource->trip[attr->index - 7] * 1000;
+		break;
+	default:
+		WARN(1, "Implementation error: unexpected attribute index %d\n",
+		     attr->index);
+		break;
+	}
+
+	return sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t show_accuracy(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+	unsigned int acc = resource->caps.accuracy;
+
+	return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
+}
+
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *devattr,
+			 char *buf)
+{
+	return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
+}
+
+#define RO_SENSOR_TEMPLATE(_label, _show, _index)	\
+	{						\
+		.label = _label,			\
+		.show  = _show,				\
+		.index = _index,			\
+	}
+
+#define RW_SENSOR_TEMPLATE(_label, _show, _set, _index)	\
+	{						\
+		.label = _label,			\
+		.show  = _show,				\
+		.set   = _set,				\
+		.index = _index,			\
+	}
+
+/* Sensor descriptions.  If you add a sensor, update NUM_SENSORS above! */
+static struct sensor_template meter_attrs[] = {
+	RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
+	RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
+	RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
+	RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
+	RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
+	RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
+		set_avg_interval, 0),
+	{},
+};
+
+static struct sensor_template misc_cap_attrs[] = {
+	RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
+	RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
+	RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
+	RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
+	{},
+};
+
+static struct sensor_template ro_cap_attrs[] = {
+	RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
+	{},
+};
+
+static struct sensor_template rw_cap_attrs[] = {
+	RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
+	{},
+};
+
+static struct sensor_template trip_attrs[] = {
+	RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
+	RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
+	{},
+};
+
+static struct sensor_template misc_attrs[] = {
+	RO_SENSOR_TEMPLATE("name", show_name, 0),
+	RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
+	RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
+	RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
+	{},
+};
+
+#undef RO_SENSOR_TEMPLATE
+#undef RW_SENSOR_TEMPLATE
+
+/* Read power domain data */
+static void remove_domain_devices(struct acpi_power_meter_resource *resource)
+{
+	int i;
+
+	if (!resource->num_domain_devices)
+		return;
+
+	for (i = 0; i < resource->num_domain_devices; i++) {
+		struct acpi_device *obj = resource->domain_devices[i];
+		if (!obj)
+			continue;
+
+		sysfs_remove_link(resource->holders_dir,
+				  kobject_name(&obj->dev.kobj));
+		put_device(&obj->dev);
+	}
+
+	kfree(resource->domain_devices);
+	kobject_put(resource->holders_dir);
+	resource->num_domain_devices = 0;
+}
+
+static int read_domain_devices(struct acpi_power_meter_resource *resource)
+{
+	int res = 0;
+	int i;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *pss;
+	acpi_status status;
+
+	status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL,
+				      &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD"));
+		return -ENODEV;
+	}
+
+	pss = buffer.pointer;
+	if (!pss ||
+	    pss->type != ACPI_TYPE_PACKAGE) {
+		dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+			"Invalid _PMD data\n");
+		res = -EFAULT;
+		goto end;
+	}
+
+	if (!pss->package.count)
+		goto end;
+
+	resource->domain_devices = kzalloc(sizeof(struct acpi_device *) *
+					   pss->package.count, GFP_KERNEL);
+	if (!resource->domain_devices) {
+		res = -ENOMEM;
+		goto end;
+	}
+
+	resource->holders_dir = kobject_create_and_add("measures",
+					&resource->acpi_dev->dev.kobj);
+	if (!resource->holders_dir) {
+		res = -ENOMEM;
+		goto exit_free;
+	}
+
+	resource->num_domain_devices = pss->package.count;
+
+	for (i = 0; i < pss->package.count; i++) {
+		struct acpi_device *obj;
+		union acpi_object *element = &(pss->package.elements[i]);
+
+		/* Refuse non-references */
+		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+			continue;
+
+		/* Create a symlink to domain objects */
+		resource->domain_devices[i] = NULL;
+		if (acpi_bus_get_device(element->reference.handle,
+					&resource->domain_devices[i]))
+			continue;
+
+		obj = resource->domain_devices[i];
+		get_device(&obj->dev);
+
+		res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,
+				      kobject_name(&obj->dev.kobj));
+		if (res) {
+			put_device(&obj->dev);
+			resource->domain_devices[i] = NULL;
+		}
+	}
+
+	res = 0;
+	goto end;
+
+exit_free:
+	kfree(resource->domain_devices);
+end:
+	kfree(buffer.pointer);
+	return res;
+}
+
+/* Registration and deregistration */
+static int register_attrs(struct acpi_power_meter_resource *resource,
+			  struct sensor_template *attrs)
+{
+	struct device *dev = &resource->acpi_dev->dev;
+	struct sensor_device_attribute *sensors =
+		&resource->sensors[resource->num_sensors];
+	int res = 0;
+
+	while (attrs->label) {
+		sensors->dev_attr.attr.name = attrs->label;
+		sensors->dev_attr.attr.mode = S_IRUGO;
+		sensors->dev_attr.show = attrs->show;
+		sensors->index = attrs->index;
+
+		if (attrs->set) {
+			sensors->dev_attr.attr.mode |= S_IWUSR;
+			sensors->dev_attr.store = attrs->set;
+		}
+
+		sysfs_attr_init(&sensors->dev_attr.attr);
+		res = device_create_file(dev, &sensors->dev_attr);
+		if (res) {
+			sensors->dev_attr.attr.name = NULL;
+			goto error;
+		}
+		sensors++;
+		resource->num_sensors++;
+		attrs++;
+	}
+
+error:
+	return res;
+}
+
+static void remove_attrs(struct acpi_power_meter_resource *resource)
+{
+	int i;
+
+	for (i = 0; i < resource->num_sensors; i++) {
+		if (!resource->sensors[i].dev_attr.attr.name)
+			continue;
+		device_remove_file(&resource->acpi_dev->dev,
+				   &resource->sensors[i].dev_attr);
+	}
+
+	remove_domain_devices(resource);
+
+	resource->num_sensors = 0;
+}
+
+static int setup_attrs(struct acpi_power_meter_resource *resource)
+{
+	int res = 0;
+
+	res = read_domain_devices(resource);
+	if (res)
+		return res;
+
+	if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
+		res = register_attrs(resource, meter_attrs);
+		if (res)
+			goto error;
+	}
+
+	if (resource->caps.flags & POWER_METER_CAN_CAP) {
+		if (!can_cap_in_hardware()) {
+			dev_err(&resource->acpi_dev->dev,
+				"Ignoring unsafe software power cap!\n");
+			goto skip_unsafe_cap;
+		}
+
+		if (resource->caps.configurable_cap)
+			res = register_attrs(resource, rw_cap_attrs);
+		else
+			res = register_attrs(resource, ro_cap_attrs);
+
+		if (res)
+			goto error;
+
+		res = register_attrs(resource, misc_cap_attrs);
+		if (res)
+			goto error;
+	}
+
+skip_unsafe_cap:
+	if (resource->caps.flags & POWER_METER_CAN_TRIP) {
+		res = register_attrs(resource, trip_attrs);
+		if (res)
+			goto error;
+	}
+
+	res = register_attrs(resource, misc_attrs);
+	if (res)
+		goto error;
+
+	return res;
+error:
+	remove_attrs(resource);
+	return res;
+}
+
+static void free_capabilities(struct acpi_power_meter_resource *resource)
+{
+	acpi_string *str;
+	int i;
+
+	str = &resource->model_number;
+	for (i = 0; i < 3; i++, str++)
+		kfree(*str);
+}
+
+static int read_capabilities(struct acpi_power_meter_resource *resource)
+{
+	int res = 0;
+	int i;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer state = { 0, NULL };
+	struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" };
+	union acpi_object *pss;
+	acpi_string *str;
+	acpi_status status;
+
+	status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL,
+				      &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC"));
+		return -ENODEV;
+	}
+
+	pss = buffer.pointer;
+	if (!pss ||
+	    pss->type != ACPI_TYPE_PACKAGE ||
+	    pss->package.count != 14) {
+		dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+			"Invalid _PMC data\n");
+		res = -EFAULT;
+		goto end;
+	}
+
+	/* Grab all the integer data at once */
+	state.length = sizeof(struct acpi_power_meter_capabilities);
+	state.pointer = &resource->caps;
+
+	status = acpi_extract_package(pss, &format, &state);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Invalid data"));
+		res = -EFAULT;
+		goto end;
+	}
+
+	if (resource->caps.units) {
+		dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+			"Unknown units %llu.\n",
+			resource->caps.units);
+		res = -EINVAL;
+		goto end;
+	}
+
+	/* Grab the string data */
+	str = &resource->model_number;
+
+	for (i = 11; i < 14; i++) {
+		union acpi_object *element = &(pss->package.elements[i]);
+
+		if (element->type != ACPI_TYPE_STRING) {
+			res = -EINVAL;
+			goto error;
+		}
+
+		*str = kzalloc(sizeof(u8) * (element->string.length + 1),
+			       GFP_KERNEL);
+		if (!*str) {
+			res = -ENOMEM;
+			goto error;
+		}
+
+		strncpy(*str, element->string.pointer, element->string.length);
+		str++;
+	}
+
+	dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");
+	goto end;
+error:
+	str = &resource->model_number;
+	for (i = 0; i < 3; i++, str++)
+		kfree(*str);
+end:
+	kfree(buffer.pointer);
+	return res;
+}
+
+/* Handle ACPI event notifications */
+static void acpi_power_meter_notify(struct acpi_device *device, u32 event)
+{
+	struct acpi_power_meter_resource *resource;
+	int res;
+
+	if (!device || !acpi_driver_data(device))
+		return;
+
+	resource = acpi_driver_data(device);
+
+	mutex_lock(&resource->lock);
+	switch (event) {
+	case METER_NOTIFY_CONFIG:
+		free_capabilities(resource);
+		res = read_capabilities(resource);
+		if (res)
+			break;
+
+		remove_attrs(resource);
+		setup_attrs(resource);
+		break;
+	case METER_NOTIFY_TRIP:
+		sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);
+		update_meter(resource);
+		break;
+	case METER_NOTIFY_CAP:
+		sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);
+		update_cap(resource);
+		break;
+	case METER_NOTIFY_INTERVAL:
+		sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);
+		update_avg_interval(resource);
+		break;
+	case METER_NOTIFY_CAPPING:
+		sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);
+		dev_info(&device->dev, "Capping in progress.\n");
+		break;
+	default:
+		WARN(1, "Unexpected event %d\n", event);
+		break;
+	}
+	mutex_unlock(&resource->lock);
+
+	acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS,
+					dev_name(&device->dev), event, 0);
+}
+
+static int acpi_power_meter_add(struct acpi_device *device)
+{
+	int res;
+	struct acpi_power_meter_resource *resource;
+
+	if (!device)
+		return -EINVAL;
+
+	resource = kzalloc(sizeof(struct acpi_power_meter_resource),
+			   GFP_KERNEL);
+	if (!resource)
+		return -ENOMEM;
+
+	resource->sensors_valid = 0;
+	resource->acpi_dev = device;
+	mutex_init(&resource->lock);
+	strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
+	device->driver_data = resource;
+
+	free_capabilities(resource);
+	res = read_capabilities(resource);
+	if (res)
+		goto exit_free;
+
+	resource->trip[0] = resource->trip[1] = -1;
+
+	res = setup_attrs(resource);
+	if (res)
+		goto exit_free;
+
+	resource->hwmon_dev = hwmon_device_register(&device->dev);
+	if (IS_ERR(resource->hwmon_dev)) {
+		res = PTR_ERR(resource->hwmon_dev);
+		goto exit_remove;
+	}
+
+	res = 0;
+	goto exit;
+
+exit_remove:
+	remove_attrs(resource);
+exit_free:
+	kfree(resource);
+exit:
+	return res;
+}
+
+static int acpi_power_meter_remove(struct acpi_device *device)
+{
+	struct acpi_power_meter_resource *resource;
+
+	if (!device || !acpi_driver_data(device))
+		return -EINVAL;
+
+	resource = acpi_driver_data(device);
+	hwmon_device_unregister(resource->hwmon_dev);
+
+	free_capabilities(resource);
+	remove_attrs(resource);
+
+	kfree(resource);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int acpi_power_meter_resume(struct device *dev)
+{
+	struct acpi_power_meter_resource *resource;
+
+	if (!dev)
+		return -EINVAL;
+
+	resource = acpi_driver_data(to_acpi_device(dev));
+	if (!resource)
+		return -EINVAL;
+
+	free_capabilities(resource);
+	read_capabilities(resource);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
+
+static struct acpi_driver acpi_power_meter_driver = {
+	.name = "power_meter",
+	.class = ACPI_POWER_METER_CLASS,
+	.ids = power_meter_ids,
+	.ops = {
+		.add = acpi_power_meter_add,
+		.remove = acpi_power_meter_remove,
+		.notify = acpi_power_meter_notify,
+		},
+	.drv.pm = &acpi_power_meter_pm,
+};
+
+/* Module init/exit routines */
+static int __init enable_cap_knobs(const struct dmi_system_id *d)
+{
+	cap_in_hardware = 1;
+	return 0;
+}
+
+static struct dmi_system_id __initdata pm_dmi_table[] = {
+	{
+		enable_cap_knobs, "IBM Active Energy Manager",
+		{
+			DMI_MATCH(DMI_SYS_VENDOR, "IBM")
+		},
+	},
+	{}
+};
+
+static int __init acpi_power_meter_init(void)
+{
+	int result;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	dmi_check_system(pm_dmi_table);
+
+	result = acpi_bus_register_driver(&acpi_power_meter_driver);
+	if (result < 0)
+		return result;
+
+	return 0;
+}
+
+static void __exit acpi_power_meter_exit(void)
+{
+	acpi_bus_unregister_driver(&acpi_power_meter_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
+MODULE_LICENSE("GPL");
+
+module_param(force_cap_on, bool, 0644);
+MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so.");
+
+module_init(acpi_power_meter_init);
+module_exit(acpi_power_meter_exit);
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
new file mode 100644
index 0000000..202c1fb
--- /dev/null
+++ b/drivers/hwmon/ad7314.c
@@ -0,0 +1,170 @@
+/*
+ * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
+ */
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/bitops.h>
+
+/*
+ * AD7314 temperature masks
+ */
+#define AD7314_TEMP_MASK		0x7FE0
+#define AD7314_TEMP_SHIFT		5
+
+/*
+ * ADT7301 and ADT7302 temperature masks
+ */
+#define ADT7301_TEMP_MASK		0x3FFF
+
+enum ad7314_variant {
+	adt7301,
+	adt7302,
+	ad7314,
+};
+
+struct ad7314_data {
+	struct spi_device	*spi_dev;
+	struct device		*hwmon_dev;
+	u16 rx ____cacheline_aligned;
+};
+
+static int ad7314_spi_read(struct ad7314_data *chip)
+{
+	int ret;
+
+	ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
+	if (ret < 0) {
+		dev_err(&chip->spi_dev->dev, "SPI read error\n");
+		return ret;
+	}
+
+	return be16_to_cpu(chip->rx);
+}
+
+static ssize_t ad7314_show_temperature(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct ad7314_data *chip = dev_get_drvdata(dev);
+	s16 data;
+	int ret;
+
+	ret = ad7314_spi_read(chip);
+	if (ret < 0)
+		return ret;
+	switch (spi_get_device_id(chip->spi_dev)->driver_data) {
+	case ad7314:
+		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
+		data = sign_extend32(data, 9);
+
+		return sprintf(buf, "%d\n", 250 * data);
+	case adt7301:
+	case adt7302:
+		/*
+		 * Documented as a 13 bit twos complement register
+		 * with a sign bit - which is a 14 bit 2's complement
+		 * register.  1lsb - 31.25 milli degrees centigrade
+		 */
+		data = ret & ADT7301_TEMP_MASK;
+		data = sign_extend32(data, 13);
+
+		return sprintf(buf, "%d\n",
+			       DIV_ROUND_CLOSEST(data * 3125, 100));
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t ad7314_show_name(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+			  ad7314_show_temperature, NULL, 0);
+
+static struct attribute *ad7314_attributes[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad7314_group = {
+	.attrs = ad7314_attributes,
+};
+
+static int ad7314_probe(struct spi_device *spi_dev)
+{
+	int ret;
+	struct ad7314_data *chip;
+
+	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi_dev, chip);
+
+	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
+	if (ret < 0)
+		return ret;
+
+	chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
+	if (IS_ERR(chip->hwmon_dev)) {
+		ret = PTR_ERR(chip->hwmon_dev);
+		goto error_remove_group;
+	}
+	chip->spi_dev = spi_dev;
+
+	return 0;
+error_remove_group:
+	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
+	return ret;
+}
+
+static int ad7314_remove(struct spi_device *spi_dev)
+{
+	struct ad7314_data *chip = spi_get_drvdata(spi_dev);
+
+	hwmon_device_unregister(chip->hwmon_dev);
+	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
+
+	return 0;
+}
+
+static const struct spi_device_id ad7314_id[] = {
+	{ "adt7301", adt7301 },
+	{ "adt7302", adt7302 },
+	{ "ad7314", ad7314 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad7314_id);
+
+static struct spi_driver ad7314_driver = {
+	.driver = {
+		.name = "ad7314",
+	},
+	.probe = ad7314_probe,
+	.remove = ad7314_remove,
+	.id_table = ad7314_id,
+};
+
+module_spi_driver(ad7314_driver);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
new file mode 100644
index 0000000..763490a
--- /dev/null
+++ b/drivers/hwmon/ad7414.c
@@ -0,0 +1,234 @@
+/*
+ * An hwmon driver for the Analog Devices AD7414
+ *
+ * Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ *   Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * Copyright (c) 2008 Spansion Inc.
+ *   Frank Edelhaeuser <frank.edelhaeuser at spansion.com>
+ *   (converted to "new style" I2C driver model, removed checkpatch.pl warnings)
+ *
+ * Based on ad7418.c
+ * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo at towertech.it>
+ *
+ * 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.
+ */
+
+#include <linux/module.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>
+#include <linux/slab.h>
+
+
+/* AD7414 registers */
+#define AD7414_REG_TEMP		0x00
+#define AD7414_REG_CONF		0x01
+#define AD7414_REG_T_HIGH	0x02
+#define AD7414_REG_T_LOW	0x03
+
+static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW };
+
+struct ad7414_data {
+	struct i2c_client	*client;
+	struct mutex		lock;	/* atomic read data updates */
+	char			valid;	/* !=0 if following fields are valid */
+	unsigned long		next_update;	/* In jiffies */
+	s16			temp_input;	/* Register values */
+	s8			temps[ARRAY_SIZE(AD7414_REG_LIMIT)];
+};
+
+/* REG: (0.25C/bit, two's complement) << 6 */
+static inline int ad7414_temp_from_reg(s16 reg)
+{
+	/*
+	 * use integer division instead of equivalent right shift to
+	 * guarantee arithmetic shift and preserve the sign
+	 */
+	return ((int)reg / 64) * 250;
+}
+
+static inline int ad7414_read(struct i2c_client *client, u8 reg)
+{
+	if (reg == AD7414_REG_TEMP)
+		return i2c_smbus_read_word_swapped(client, reg);
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct ad7414_data *ad7414_update_device(struct device *dev)
+{
+	struct ad7414_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->next_update) || !data->valid) {
+		int value, i;
+
+		dev_dbg(&client->dev, "starting ad7414 update\n");
+
+		value = ad7414_read(client, AD7414_REG_TEMP);
+		if (value < 0)
+			dev_dbg(&client->dev, "AD7414_REG_TEMP err %d\n",
+				value);
+		else
+			data->temp_input = value;
+
+		for (i = 0; i < ARRAY_SIZE(AD7414_REG_LIMIT); ++i) {
+			value = ad7414_read(client, AD7414_REG_LIMIT[i]);
+			if (value < 0)
+				dev_dbg(&client->dev, "AD7414 reg %d err %d\n",
+					AD7414_REG_LIMIT[i], value);
+			else
+				data->temps[i] = value;
+		}
+
+		data->next_update = jiffies + HZ + HZ / 2;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct ad7414_data *data = ad7414_update_device(dev);
+	return sprintf(buf, "%d\n", ad7414_temp_from_reg(data->temp_input));
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+
+static ssize_t show_max_min(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct ad7414_data *data = ad7414_update_device(dev);
+	return sprintf(buf, "%d\n", data->temps[index] * 1000);
+}
+
+static ssize_t set_max_min(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct ad7414_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int index = to_sensor_dev_attr(attr)->index;
+	u8 reg = AD7414_REG_LIMIT[index];
+	long temp;
+	int ret = kstrtol(buf, 10, &temp);
+
+	if (ret < 0)
+		return ret;
+
+	temp = clamp_val(temp, -40000, 85000);
+	temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
+
+	mutex_lock(&data->lock);
+	data->temps[index] = temp;
+	ad7414_write(client, reg, temp);
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  show_max_min, set_max_min, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  show_max_min, set_max_min, 1);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct ad7414_data *data = ad7414_update_device(dev);
+	int value = (data->temp_input >> bitnr) & 1;
+	return sprintf(buf, "%d\n", value);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+static struct attribute *ad7414_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(ad7414);
+
+static int ad7414_probe(struct i2c_client *client,
+			const struct i2c_device_id *dev_id)
+{
+	struct device *dev = &client->dev;
+	struct ad7414_data *data;
+	struct device *hwmon_dev;
+	int conf;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EOPNOTSUPP;
+
+	data = devm_kzalloc(dev, sizeof(struct ad7414_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->lock);
+
+	dev_info(&client->dev, "chip found\n");
+
+	/* Make sure the chip is powered up. */
+	conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF);
+	if (conf < 0)
+		dev_warn(dev, "ad7414_probe unable to read config register.\n");
+	else {
+		conf &= ~(1 << 7);
+		i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf);
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   client->name,
+							   data, ad7414_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ad7414_id[] = {
+	{ "ad7414", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ad7414_id);
+
+static struct i2c_driver ad7414_driver = {
+	.driver = {
+		.name	= "ad7414",
+	},
+	.probe	= ad7414_probe,
+	.id_table = ad7414_id,
+};
+
+module_i2c_driver(ad7414_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr at denx.de>, "
+	      "Frank Edelhaeuser <frank.edelhaeuser at spansion.com>");
+
+MODULE_DESCRIPTION("AD7414 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
new file mode 100644
index 0000000..a01b731
--- /dev/null
+++ b/drivers/hwmon/ad7418.c
@@ -0,0 +1,275 @@
+/*
+ * An hwmon driver for the Analog Devices AD7416/17/18
+ * Copyright (C) 2006-07 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * Based on lm75.c
+ * Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ *
+ * 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.
+ */
+
+#include <linux/module.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/delay.h>
+#include <linux/slab.h>
+
+#include "lm75.h"
+
+#define DRV_VERSION "0.4"
+
+enum chips { ad7416, ad7417, ad7418 };
+
+/* AD7418 registers */
+#define AD7418_REG_TEMP_IN	0x00
+#define AD7418_REG_CONF		0x01
+#define AD7418_REG_TEMP_HYST	0x02
+#define AD7418_REG_TEMP_OS	0x03
+#define AD7418_REG_ADC		0x04
+#define AD7418_REG_CONF2	0x05
+
+#define AD7418_REG_ADC_CH(x)	((x) << 5)
+#define AD7418_CH_TEMP		AD7418_REG_ADC_CH(0)
+
+static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
+					AD7418_REG_TEMP_HYST,
+					AD7418_REG_TEMP_OS };
+
+struct ad7418_data {
+	struct i2c_client	*client;
+	enum chips		type;
+	struct mutex		lock;
+	int			adc_max;	/* number of ADC channels */
+	char			valid;
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[3];	/* Register values */
+	u16			in[4];
+};
+
+static struct ad7418_data *ad7418_update_device(struct device *dev)
+{
+	struct ad7418_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+		u8 cfg;
+		int i, ch;
+
+		/* read config register and clear channel bits */
+		cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+		cfg &= 0x1F;
+
+		i2c_smbus_write_byte_data(client, AD7418_REG_CONF,
+						cfg | AD7418_CH_TEMP);
+		udelay(30);
+
+		for (i = 0; i < 3; i++) {
+			data->temp[i] =
+				i2c_smbus_read_word_swapped(client,
+						AD7418_REG_TEMP[i]);
+		}
+
+		for (i = 0, ch = 4; i < data->adc_max; i++, ch--) {
+			i2c_smbus_write_byte_data(client,
+					AD7418_REG_CONF,
+					cfg | AD7418_REG_ADC_CH(ch));
+
+			udelay(15);
+			data->in[data->adc_max - 1 - i] =
+				i2c_smbus_read_word_swapped(client,
+						AD7418_REG_ADC);
+		}
+
+		/* restore old configuration value */
+		i2c_smbus_write_word_swapped(client, AD7418_REG_CONF, cfg);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+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 ad7418_data *data = ad7418_update_device(dev);
+	return sprintf(buf, "%d\n",
+		LM75_TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct ad7418_data *data = ad7418_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		((data->in[attr->index] >> 6) * 2500 + 512) / 1024);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct ad7418_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	int ret = kstrtol(buf, 10, &temp);
+
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->lock);
+	data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
+	i2c_smbus_write_word_swapped(client,
+				     AD7418_REG_TEMP[attr->index],
+				     data->temp[attr->index]);
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+				show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+				show_temp, set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
+
+static struct attribute *ad7416_attrs[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(ad7416);
+
+static struct attribute *ad7417_attrs[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(ad7417);
+
+static struct attribute *ad7418_attrs[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(ad7418);
+
+static void ad7418_init_client(struct i2c_client *client)
+{
+	struct ad7418_data *data = i2c_get_clientdata(client);
+
+	int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+	if (reg < 0) {
+		dev_err(&client->dev, "cannot read configuration register\n");
+	} else {
+		dev_info(&client->dev, "configuring for mode 1\n");
+		i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
+
+		if (data->type == ad7417 || data->type == ad7418)
+			i2c_smbus_write_byte_data(client,
+						AD7418_REG_CONF2, 0x00);
+	}
+}
+
+static int ad7418_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct i2c_adapter *adapter = client->adapter;
+	struct ad7418_data *data;
+	struct device *hwmon_dev;
+	const struct attribute_group **attr_groups = NULL;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		return -EOPNOTSUPP;
+
+	data = devm_kzalloc(dev, sizeof(struct ad7418_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+
+	mutex_init(&data->lock);
+	data->client = client;
+	data->type = id->driver_data;
+
+	switch (data->type) {
+	case ad7416:
+		data->adc_max = 0;
+		attr_groups = ad7416_groups;
+		break;
+
+	case ad7417:
+		data->adc_max = 4;
+		attr_groups = ad7417_groups;
+		break;
+
+	case ad7418:
+		data->adc_max = 1;
+		attr_groups = ad7418_groups;
+		break;
+	}
+
+	dev_info(dev, "%s chip found\n", client->name);
+
+	/* Initialize the AD7418 chip */
+	ad7418_init_client(client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   client->name,
+							   data, attr_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ad7418_id[] = {
+	{ "ad7416", ad7416 },
+	{ "ad7417", ad7417 },
+	{ "ad7418", ad7418 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad7418_id);
+
+static struct i2c_driver ad7418_driver = {
+	.driver = {
+		.name	= "ad7418",
+	},
+	.probe		= ad7418_probe,
+	.id_table	= ad7418_id,
+};
+
+module_i2c_driver(ad7418_driver);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("AD7416/17/18 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
new file mode 100644
index 0000000..ad2b47e
--- /dev/null
+++ b/drivers/hwmon/adc128d818.c
@@ -0,0 +1,492 @@
+/*
+ * Driver for TI ADC128D818 System Monitor with Temperature Sensor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * Derived from lm80.c
+ * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *			     and Philip Edelbrock <phil@netroedge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/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/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+
+/* Addresses to scan
+ * The chip also supports addresses 0x35..0x37. Don't scan those addresses
+ * since they are also used by some EEPROMs, which may result in false
+ * positives.
+ */
+static const unsigned short normal_i2c[] = {
+	0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* registers */
+#define ADC128_REG_IN_MAX(nr)		(0x2a + (nr) * 2)
+#define ADC128_REG_IN_MIN(nr)		(0x2b + (nr) * 2)
+#define ADC128_REG_IN(nr)		(0x20 + (nr))
+
+#define ADC128_REG_TEMP			0x27
+#define ADC128_REG_TEMP_MAX		0x38
+#define ADC128_REG_TEMP_HYST		0x39
+
+#define ADC128_REG_CONFIG		0x00
+#define ADC128_REG_ALARM		0x01
+#define ADC128_REG_MASK			0x03
+#define ADC128_REG_CONV_RATE		0x07
+#define ADC128_REG_ONESHOT		0x09
+#define ADC128_REG_SHUTDOWN		0x0a
+#define ADC128_REG_CONFIG_ADV		0x0b
+#define ADC128_REG_BUSY_STATUS		0x0c
+
+#define ADC128_REG_MAN_ID		0x3e
+#define ADC128_REG_DEV_ID		0x3f
+
+struct adc128_data {
+	struct i2c_client *client;
+	struct regulator *regulator;
+	int vref;		/* Reference voltage in mV */
+	struct mutex update_lock;
+	bool valid;		/* true if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u16 in[3][7];		/* Register value, normalized to 12 bit
+				 * 0: input voltage
+				 * 1: min limit
+				 * 2: max limit
+				 */
+	s16 temp[3];		/* Register value, normalized to 9 bit
+				 * 0: sensor 1: limit 2: hyst
+				 */
+	u8 alarms;		/* alarm register value */
+};
+
+static struct adc128_data *adc128_update_device(struct device *dev)
+{
+	struct adc128_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct adc128_data *ret = data;
+	int i, rv;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		for (i = 0; i < 7; i++) {
+			rv = i2c_smbus_read_word_swapped(client,
+							 ADC128_REG_IN(i));
+			if (rv < 0)
+				goto abort;
+			data->in[0][i] = rv >> 4;
+
+			rv = i2c_smbus_read_byte_data(client,
+						      ADC128_REG_IN_MIN(i));
+			if (rv < 0)
+				goto abort;
+			data->in[1][i] = rv << 4;
+
+			rv = i2c_smbus_read_byte_data(client,
+						      ADC128_REG_IN_MAX(i));
+			if (rv < 0)
+				goto abort;
+			data->in[2][i] = rv << 4;
+		}
+
+		rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP);
+		if (rv < 0)
+			goto abort;
+		data->temp[0] = rv >> 7;
+
+		rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX);
+		if (rv < 0)
+			goto abort;
+		data->temp[1] = rv << 1;
+
+		rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST);
+		if (rv < 0)
+			goto abort;
+		data->temp[2] = rv << 1;
+
+		rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM);
+		if (rv < 0)
+			goto abort;
+		data->alarms |= rv;
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+	goto done;
+
+abort:
+	ret = ERR_PTR(rv);
+	data->valid = false;
+done:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct adc128_data *data = adc128_update_device(dev);
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095);
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct adc128_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	u8 reg, regval;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/* 10 mV LSB on limit registers */
+	regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
+	data->in[index][nr] = regval << 4;
+	reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
+	i2c_smbus_write_byte_data(data->client, reg, regval);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t adc128_show_temp(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct adc128_data *data = adc128_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int temp;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = sign_extend32(data->temp[index], 8);
+	return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
+}
+
+static ssize_t adc128_set_temp(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct adc128_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+	s8 regval;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+	data->temp[index] = regval << 1;
+	i2c_smbus_write_byte_data(data->client,
+				  index == 1 ? ADC128_REG_TEMP_MAX
+					     : ADC128_REG_TEMP_HYST,
+				  regval);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t adc128_show_alarm(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adc128_data *data = adc128_update_device(dev);
+	int mask = 1 << to_sensor_dev_attr(attr)->index;
+	u8 alarms;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	/*
+	 * Clear an alarm after reporting it to user space. If it is still
+	 * active, the next update sequence will set the alarm bit again.
+	 */
+	alarms = data->alarms;
+	data->alarms &= ~mask;
+
+	return sprintf(buf, "%u\n", !!(alarms & mask));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO,
+			    adc128_show_in, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO,
+			    adc128_show_in, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO,
+			    adc128_show_in, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO,
+			    adc128_show_in, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO,
+			    adc128_show_in, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO,
+			    adc128_show_in, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO,
+			    adc128_show_in, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+			    adc128_show_in, adc128_set_in, 6, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  adc128_show_temp, adc128_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  adc128_show_temp, adc128_set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7);
+
+static struct attribute *adc128_attrs[] = {
+	&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_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_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(adc128);
+
+static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	int man_id, dev_id;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID);
+	dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID);
+	if (man_id != 0x01 || dev_id != 0x09)
+		return -ENODEV;
+
+	/* Check unused bits for confirmation */
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4)
+		return -ENODEV;
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe)
+		return -ENODEV;
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe)
+		return -ENODEV;
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe)
+		return -ENODEV;
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8)
+		return -ENODEV;
+	if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc)
+		return -ENODEV;
+
+	strlcpy(info->type, "adc128d818", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int adc128_init_client(struct adc128_data *data)
+{
+	struct i2c_client *client = data->client;
+	int err;
+
+	/*
+	 * Reset chip to defaults.
+	 * This makes most other initializations unnecessary.
+	 */
+	err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80);
+	if (err)
+		return err;
+
+	/* Start monitoring */
+	err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01);
+	if (err)
+		return err;
+
+	/* If external vref is selected, configure the chip to use it */
+	if (data->regulator) {
+		err = i2c_smbus_write_byte_data(client,
+						ADC128_REG_CONFIG_ADV, 0x01);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int adc128_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct regulator *regulator;
+	struct device *hwmon_dev;
+	struct adc128_data *data;
+	int err, vref;
+
+	data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* vref is optional. If specified, is used as chip reference voltage */
+	regulator = devm_regulator_get_optional(dev, "vref");
+	if (!IS_ERR(regulator)) {
+		data->regulator = regulator;
+		err = regulator_enable(regulator);
+		if (err < 0)
+			return err;
+		vref = regulator_get_voltage(regulator);
+		if (vref < 0) {
+			err = vref;
+			goto error;
+		}
+		data->vref = DIV_ROUND_CLOSEST(vref, 1000);
+	} else {
+		data->vref = 2560;	/* 2.56V, in mV */
+	}
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the chip */
+	err = adc128_init_client(data);
+	if (err < 0)
+		goto error;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, adc128_groups);
+	if (IS_ERR(hwmon_dev)) {
+		err = PTR_ERR(hwmon_dev);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	if (data->regulator)
+		regulator_disable(data->regulator);
+	return err;
+}
+
+static int adc128_remove(struct i2c_client *client)
+{
+	struct adc128_data *data = i2c_get_clientdata(client);
+
+	if (data->regulator)
+		regulator_disable(data->regulator);
+
+	return 0;
+}
+
+static const struct i2c_device_id adc128_id[] = {
+	{ "adc128d818", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adc128_id);
+
+static struct i2c_driver adc128_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adc128d818",
+	},
+	.probe		= adc128_probe,
+	.remove		= adc128_remove,
+	.id_table	= adc128_id,
+	.detect		= adc128_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adc128_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Driver for ADC128D818");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c
new file mode 100644
index 0000000..69e0bb9
--- /dev/null
+++ b/drivers/hwmon/adcxx.c
@@ -0,0 +1,247 @@
+/*
+ * adcxx.c
+ *
+ * The adcxx4s is an AD converter family from National Semiconductor (NS).
+ *
+ * Copyright (c) 2008 Marc Pignat <marc.pignat@hevs.ch>
+ *
+ * The adcxx4s communicates with a host processor via an SPI/Microwire Bus
+ * interface. This driver supports the whole family of devices with name
+ * ADC<bb><c>S<sss>, where
+ * * bb is the resolution in number of bits (8, 10, 12)
+ * * c is the number of channels (1, 2, 4, 8)
+ * * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 kSPS
+ *   and 101 for 1 MSPS)
+ *
+ * Complete datasheets are available at National's website here:
+ * http://www.national.com/ds/DC/ADC<bb><c>S<sss>.pdf
+ *
+ * Handling of 8, 10 and 12 bits converters are the same, the
+ * unavailable bits are 0 :)
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mutex.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+
+#define DRVNAME		"adcxx"
+
+struct adcxx {
+	struct device *hwmon_dev;
+	struct mutex lock;
+	u32 channels;
+	u32 reference; /* in millivolts */
+};
+
+/* sysfs hook function */
+static ssize_t adcxx_read(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adcxx *adc = spi_get_drvdata(spi);
+	u8 tx_buf[2];
+	u8 rx_buf[2];
+	int status;
+	u32 value;
+
+	if (mutex_lock_interruptible(&adc->lock))
+		return -ERESTARTSYS;
+
+	if (adc->channels == 1) {
+		status = spi_read(spi, rx_buf, sizeof(rx_buf));
+	} else {
+		tx_buf[0] = attr->index << 3; /* other bits are don't care */
+		status = spi_write_then_read(spi, tx_buf, sizeof(tx_buf),
+						rx_buf, sizeof(rx_buf));
+	}
+	if (status < 0) {
+		dev_warn(dev, "SPI synch. transfer failed with status %d\n",
+				status);
+		goto out;
+	}
+
+	value = (rx_buf[0] << 8) + rx_buf[1];
+	dev_dbg(dev, "raw value = 0x%x\n", value);
+
+	value = value * adc->reference >> 12;
+	status = sprintf(buf, "%d\n", value);
+out:
+	mutex_unlock(&adc->lock);
+	return status;
+}
+
+static ssize_t adcxx_show_min(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	/* The minimum reference is 0 for this chip family */
+	return sprintf(buf, "0\n");
+}
+
+static ssize_t adcxx_show_max(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct adcxx *adc = spi_get_drvdata(spi);
+	u32 reference;
+
+	if (mutex_lock_interruptible(&adc->lock))
+		return -ERESTARTSYS;
+
+	reference = adc->reference;
+
+	mutex_unlock(&adc->lock);
+
+	return sprintf(buf, "%d\n", reference);
+}
+
+static ssize_t adcxx_set_max(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct adcxx *adc = spi_get_drvdata(spi);
+	unsigned long value;
+
+	if (kstrtoul(buf, 10, &value))
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&adc->lock))
+		return -ERESTARTSYS;
+
+	adc->reference = value;
+
+	mutex_unlock(&adc->lock);
+
+	return count;
+}
+
+static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
+static struct sensor_device_attribute ad_input[] = {
+	SENSOR_ATTR(name, S_IRUGO, adcxx_show_name, NULL, 0),
+	SENSOR_ATTR(in_min, S_IRUGO, adcxx_show_min, NULL, 0),
+	SENSOR_ATTR(in_max, S_IWUSR | S_IRUGO, adcxx_show_max,
+					adcxx_set_max, 0),
+	SENSOR_ATTR(in0_input, S_IRUGO, adcxx_read, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, adcxx_read, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, adcxx_read, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, adcxx_read, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, adcxx_read, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, adcxx_read, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, adcxx_read, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, adcxx_read, NULL, 7),
+};
+
+/*----------------------------------------------------------------------*/
+
+static int adcxx_probe(struct spi_device *spi)
+{
+	int channels = spi_get_device_id(spi)->driver_data;
+	struct adcxx *adc;
+	int status;
+	int i;
+
+	adc = devm_kzalloc(&spi->dev, sizeof(*adc), GFP_KERNEL);
+	if (!adc)
+		return -ENOMEM;
+
+	/* set a default value for the reference */
+	adc->reference = 3300;
+	adc->channels = channels;
+	mutex_init(&adc->lock);
+
+	mutex_lock(&adc->lock);
+
+	spi_set_drvdata(spi, adc);
+
+	for (i = 0; i < 3 + adc->channels; i++) {
+		status = device_create_file(&spi->dev, &ad_input[i].dev_attr);
+		if (status) {
+			dev_err(&spi->dev, "device_create_file failed.\n");
+			goto out_err;
+		}
+	}
+
+	adc->hwmon_dev = hwmon_device_register(&spi->dev);
+	if (IS_ERR(adc->hwmon_dev)) {
+		dev_err(&spi->dev, "hwmon_device_register failed.\n");
+		status = PTR_ERR(adc->hwmon_dev);
+		goto out_err;
+	}
+
+	mutex_unlock(&adc->lock);
+	return 0;
+
+out_err:
+	for (i--; i >= 0; i--)
+		device_remove_file(&spi->dev, &ad_input[i].dev_attr);
+
+	mutex_unlock(&adc->lock);
+	return status;
+}
+
+static int adcxx_remove(struct spi_device *spi)
+{
+	struct adcxx *adc = spi_get_drvdata(spi);
+	int i;
+
+	mutex_lock(&adc->lock);
+	hwmon_device_unregister(adc->hwmon_dev);
+	for (i = 0; i < 3 + adc->channels; i++)
+		device_remove_file(&spi->dev, &ad_input[i].dev_attr);
+
+	mutex_unlock(&adc->lock);
+
+	return 0;
+}
+
+static const struct spi_device_id adcxx_ids[] = {
+	{ "adcxx1s", 1 },
+	{ "adcxx2s", 2 },
+	{ "adcxx4s", 4 },
+	{ "adcxx8s", 8 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, adcxx_ids);
+
+static struct spi_driver adcxx_driver = {
+	.driver = {
+		.name	= "adcxx",
+	},
+	.id_table = adcxx_ids,
+	.probe	= adcxx_probe,
+	.remove	= adcxx_remove,
+};
+
+module_spi_driver(adcxx_driver);
+
+MODULE_AUTHOR("Marc Pignat");
+MODULE_DESCRIPTION("National Semiconductor adcxx8sxxx Linux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
new file mode 100644
index 0000000..1fdcc3e
--- /dev/null
+++ b/drivers/hwmon/adm1021.c
@@ -0,0 +1,506 @@
+/*
+ * adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
+ *			     Philip Edelbrock <phil@netroedge.com>
+ *
+ * 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>
+
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+enum chips {
+	adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066 };
+
+/* adm1021 constants specified below */
+
+/* The adm1021 registers */
+/* Read-only */
+/* For nr in 0-1 */
+#define ADM1021_REG_TEMP(nr)		(nr)
+#define ADM1021_REG_STATUS		0x02
+/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
+#define ADM1021_REG_MAN_ID		0xFE
+/* ADM1021 = 0x0X, ADM1023 = 0x3X */
+#define ADM1021_REG_DEV_ID		0xFF
+/* These use different addresses for reading/writing */
+#define ADM1021_REG_CONFIG_R		0x03
+#define ADM1021_REG_CONFIG_W		0x09
+#define ADM1021_REG_CONV_RATE_R		0x04
+#define ADM1021_REG_CONV_RATE_W		0x0A
+/* These are for the ADM1023's additional precision on the remote temp sensor */
+#define ADM1023_REG_REM_TEMP_PREC	0x10
+#define ADM1023_REG_REM_OFFSET		0x11
+#define ADM1023_REG_REM_OFFSET_PREC	0x12
+#define ADM1023_REG_REM_TOS_PREC	0x13
+#define ADM1023_REG_REM_THYST_PREC	0x14
+/* limits */
+/* For nr in 0-1 */
+#define ADM1021_REG_TOS_R(nr)		(0x05 + 2 * (nr))
+#define ADM1021_REG_TOS_W(nr)		(0x0B + 2 * (nr))
+#define ADM1021_REG_THYST_R(nr)		(0x06 + 2 * (nr))
+#define ADM1021_REG_THYST_W(nr)		(0x0C + 2 * (nr))
+/* write-only */
+#define ADM1021_REG_ONESHOT		0x0F
+
+/* Initial values */
+
+/*
+ * Note: Even though I left the low and high limits named os and hyst,
+ * they don't quite work like a thermostat the way the LM75 does.  I.e.,
+ * a lower temp than THYST actually triggers an alarm instead of
+ * clearing it.  Weird, ey?   --Phil
+ */
+
+/* Each client has this additional data */
+struct adm1021_data {
+	struct i2c_client *client;
+	enum chips type;
+
+	const struct attribute_group *groups[3];
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	char low_power;		/* !=0 if device in low power mode */
+	unsigned long last_updated;	/* In jiffies */
+
+	int temp_max[2];		/* Register values */
+	int temp_min[2];
+	int temp[2];
+	u8 alarms;
+	/* Special values for ADM1023 only */
+	u8 remote_temp_offset;
+	u8 remote_temp_offset_prec;
+};
+
+/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
+static bool read_only;
+
+static struct adm1021_data *adm1021_update_device(struct device *dev)
+{
+	struct adm1021_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int i;
+
+		dev_dbg(dev, "Starting adm1021 update\n");
+
+		for (i = 0; i < 2; i++) {
+			data->temp[i] = 1000 *
+				(s8) i2c_smbus_read_byte_data(
+					client, ADM1021_REG_TEMP(i));
+			data->temp_max[i] = 1000 *
+				(s8) i2c_smbus_read_byte_data(
+					client, ADM1021_REG_TOS_R(i));
+			if (data->type != lm84) {
+				data->temp_min[i] = 1000 *
+				  (s8) i2c_smbus_read_byte_data(client,
+							ADM1021_REG_THYST_R(i));
+			}
+		}
+		data->alarms = i2c_smbus_read_byte_data(client,
+						ADM1021_REG_STATUS) & 0x7c;
+		if (data->type == adm1023) {
+			/*
+			 * The ADM1023 provides 3 extra bits of precision for
+			 * the remote sensor in extra registers.
+			 */
+			data->temp[1] += 125 * (i2c_smbus_read_byte_data(
+				client, ADM1023_REG_REM_TEMP_PREC) >> 5);
+			data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
+				client, ADM1023_REG_REM_TOS_PREC) >> 5);
+			data->temp_min[1] += 125 * (i2c_smbus_read_byte_data(
+				client, ADM1023_REG_REM_THYST_PREC) >> 5);
+			data->remote_temp_offset =
+				i2c_smbus_read_byte_data(client,
+						ADM1023_REG_REM_OFFSET);
+			data->remote_temp_offset_prec =
+				i2c_smbus_read_byte_data(client,
+						ADM1023_REG_REM_OFFSET_PREC);
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct adm1021_data *data = adm1021_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->temp[index]);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct adm1021_data *data = adm1021_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->temp_max[index]);
+}
+
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct adm1021_data *data = adm1021_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->temp_min[index]);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1021_data *data = adm1021_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
+static ssize_t show_alarms(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct adm1021_data *data = adm1021_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct adm1021_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	int reg_val, err;
+
+	err = kstrtol(buf, 10, &temp);
+	if (err)
+		return err;
+	temp /= 1000;
+
+	mutex_lock(&data->update_lock);
+	reg_val = clamp_val(temp, -128, 127);
+	data->temp_max[index] = reg_val * 1000;
+	if (!read_only)
+		i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
+					  reg_val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct adm1021_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	int reg_val, err;
+
+	err = kstrtol(buf, 10, &temp);
+	if (err)
+		return err;
+	temp /= 1000;
+
+	mutex_lock(&data->update_lock);
+	reg_val = clamp_val(temp, -128, 127);
+	data->temp_min[index] = reg_val * 1000;
+	if (!read_only)
+		i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
+					  reg_val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_low_power(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct adm1021_data *data = adm1021_update_device(dev);
+	return sprintf(buf, "%d\n", data->low_power);
+}
+
+static ssize_t set_low_power(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct adm1021_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	char low_power;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	low_power = val != 0;
+
+	mutex_lock(&data->update_lock);
+	if (low_power != data->low_power) {
+		int config = i2c_smbus_read_byte_data(
+			client, ADM1021_REG_CONFIG_R);
+		data->low_power = low_power;
+		i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
+			(config & 0xBF) | (low_power << 6));
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+			  set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+			  set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+			  set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+			  set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(low_power, S_IWUSR | S_IRUGO, show_low_power, set_low_power);
+
+static struct attribute *adm1021_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_low_power.attr,
+	NULL
+};
+
+static const struct attribute_group adm1021_group = {
+	.attrs = adm1021_attributes,
+};
+
+static struct attribute *adm1021_min_attributes[] = {
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adm1021_min_group = {
+	.attrs = adm1021_min_attributes,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1021_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	const char *type_name;
+	int conv_rate, status, config, man_id, dev_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_debug("detect failed, smbus byte data not supported!\n");
+		return -ENODEV;
+	}
+
+	status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
+	conv_rate = i2c_smbus_read_byte_data(client,
+					     ADM1021_REG_CONV_RATE_R);
+	config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
+
+	/* Check unused bits */
+	if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
+		pr_debug("detect failed, chip not detected!\n");
+		return -ENODEV;
+	}
+
+	/* Determine the chip type. */
+	man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
+	dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
+
+	if (man_id < 0 || dev_id < 0)
+		return -ENODEV;
+
+	if (man_id == 0x4d && dev_id == 0x01)
+		type_name = "max1617a";
+	else if (man_id == 0x41) {
+		if ((dev_id & 0xF0) == 0x30)
+			type_name = "adm1023";
+		else if ((dev_id & 0xF0) == 0x00)
+			type_name = "adm1021";
+		else
+			return -ENODEV;
+	} else if (man_id == 0x49)
+		type_name = "thmc10";
+	else if (man_id == 0x23)
+		type_name = "gl523sm";
+	else if (man_id == 0x54)
+		type_name = "mc1066";
+	else {
+		int lte, rte, lhi, rhi, llo, rlo;
+
+		/* extra checks for LM84 and MAX1617 to avoid misdetections */
+
+		llo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(0));
+		rlo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(1));
+
+		/* fail if any of the additional register reads failed */
+		if (llo < 0 || rlo < 0)
+			return -ENODEV;
+
+		lte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(0));
+		rte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(1));
+		lhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(0));
+		rhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(1));
+
+		/*
+		 * Fail for negative temperatures and negative high limits.
+		 * This check also catches read errors on the tested registers.
+		 */
+		if ((s8)lte < 0 || (s8)rte < 0 || (s8)lhi < 0 || (s8)rhi < 0)
+			return -ENODEV;
+
+		/* fail if all registers hold the same value */
+		if (lte == rte && lte == lhi && lte == rhi && lte == llo
+		    && lte == rlo)
+			return -ENODEV;
+
+		/*
+		 * LM84 Mfr ID is in a different place,
+		 * and it has more unused bits.
+		 */
+		if (conv_rate == 0x00
+		    && (config & 0x7F) == 0x00
+		    && (status & 0xAB) == 0x00) {
+			type_name = "lm84";
+		} else {
+			/* fail if low limits are larger than high limits */
+			if ((s8)llo > lhi || (s8)rlo > rhi)
+				return -ENODEV;
+			type_name = "max1617";
+		}
+	}
+
+	pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
+		 type_name, i2c_adapter_id(adapter), client->addr);
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adm1021_init_client(struct i2c_client *client)
+{
+	/* Enable ADC and disable suspend mode */
+	i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
+		i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
+	/* Set Conversion rate to 1/sec (this can be tinkered with) */
+	i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
+}
+
+static int adm1021_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct adm1021_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct adm1021_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->type = id->driver_data;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the ADM1021 chip */
+	if (data->type != lm84 && !read_only)
+		adm1021_init_client(client);
+
+	data->groups[0] = &adm1021_group;
+	if (data->type != lm84)
+		data->groups[1] = &adm1021_min_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm1021_id[] = {
+	{ "adm1021", adm1021 },
+	{ "adm1023", adm1023 },
+	{ "max1617", max1617 },
+	{ "max1617a", max1617a },
+	{ "thmc10", thmc10 },
+	{ "lm84", lm84 },
+	{ "gl523sm", gl523sm },
+	{ "mc1066", mc1066 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1021_id);
+
+static struct i2c_driver adm1021_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adm1021",
+	},
+	.probe		= adm1021_probe,
+	.id_table	= adm1021_id,
+	.detect		= adm1021_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm1021_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+		"Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("adm1021 driver");
+MODULE_LICENSE("GPL");
+
+module_param(read_only, bool, 0);
+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
new file mode 100644
index 0000000..d6c767a
--- /dev/null
+++ b/drivers/hwmon/adm1025.c
@@ -0,0 +1,582 @@
+/*
+ * adm1025.c
+ *
+ * Copyright (C) 2000       Chen-Yuan Wu <gwu@esoft.com>
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
+ *
+ * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
+ * voltages (including its own power source) and up to two temperatures
+ * (its own plus up to one external one). Voltages are scaled internally
+ * (which is not the common way) with ratios such that the nominal value
+ * of each voltage correspond to a register value of 192 (which means a
+ * resolution of about 0.5% of the nominal value). Temperature values are
+ * reported with a 1 deg resolution and a 3 deg accuracy. Complete
+ * datasheet can be obtained from Analog's website at:
+ *   http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025
+ *
+ * This driver also supports the ADM1025A, which differs from the ADM1025
+ * only in that it has "open-drain VID inputs while the ADM1025 has
+ * on-chip 100k pull-ups on the VID inputs". It doesn't make any
+ * difference for us.
+ *
+ * This driver also supports the NE1619, a sensor chip made by Philips.
+ * That chip is similar to the ADM1025A, with a few differences. The only
+ * difference that matters to us is that the NE1619 has only two possible
+ * addresses while the ADM1025A has a third one. Complete datasheet can be
+ * obtained from Philips's website at:
+ *   http://www.semiconductors.philips.com/pip/NE1619DS.html
+ *
+ * Since the ADM1025 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * 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/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e.
+ * NE1619 has two possible addresses: 0x2c and 0x2d.
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips { adm1025, ne1619 };
+
+/*
+ * The ADM1025 registers
+ */
+
+#define ADM1025_REG_MAN_ID		0x3E
+#define ADM1025_REG_CHIP_ID		0x3F
+#define ADM1025_REG_CONFIG		0x40
+#define ADM1025_REG_STATUS1		0x41
+#define ADM1025_REG_STATUS2		0x42
+#define ADM1025_REG_IN(nr)		(0x20 + (nr))
+#define ADM1025_REG_IN_MAX(nr)		(0x2B + (nr) * 2)
+#define ADM1025_REG_IN_MIN(nr)		(0x2C + (nr) * 2)
+#define ADM1025_REG_TEMP(nr)		(0x26 + (nr))
+#define ADM1025_REG_TEMP_HIGH(nr)	(0x37 + (nr) * 2)
+#define ADM1025_REG_TEMP_LOW(nr)	(0x38 + (nr) * 2)
+#define ADM1025_REG_VID			0x47
+#define ADM1025_REG_VID4		0x49
+
+/*
+ * Conversions and various macros
+ * The ADM1025 uses signed 8-bit values for temperatures.
+ */
+
+static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
+
+#define IN_FROM_REG(reg, scale)	(((reg) * (scale) + 96) / 192)
+#define IN_TO_REG(val, scale)	((val) <= 0 ? 0 : \
+				 (val) * 192 >= (scale) * 255 ? 255 : \
+				 ((val) * 192 + (scale) / 2) / (scale))
+
+#define TEMP_FROM_REG(reg)	((reg) * 1000)
+#define TEMP_TO_REG(val)	((val) <= -127500 ? -128 : \
+				 (val) >= 126500 ? 127 : \
+				 (((val) < 0 ? (val) - 500 : \
+				   (val) + 500) / 1000))
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct adm1025_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	u8 in[6];		/* register value */
+	u8 in_max[6];		/* register value */
+	u8 in_min[6];		/* register value */
+	s8 temp[2];		/* register value */
+	s8 temp_min[2];		/* register value */
+	s8 temp_max[2];		/* register value */
+	u16 alarms;		/* register values, combined */
+	u8 vid;			/* register values, combined */
+	u8 vrm;
+};
+
+static struct adm1025_data *adm1025_update_device(struct device *dev)
+{
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+		int i;
+
+		dev_dbg(&client->dev, "Updating data.\n");
+		for (i = 0; i < 6; i++) {
+			data->in[i] = i2c_smbus_read_byte_data(client,
+				      ADM1025_REG_IN(i));
+			data->in_min[i] = i2c_smbus_read_byte_data(client,
+					  ADM1025_REG_IN_MIN(i));
+			data->in_max[i] = i2c_smbus_read_byte_data(client,
+					  ADM1025_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 2; i++) {
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+					ADM1025_REG_TEMP(i));
+			data->temp_min[i] = i2c_smbus_read_byte_data(client,
+					    ADM1025_REG_TEMP_LOW(i));
+			data->temp_max[i] = i2c_smbus_read_byte_data(client,
+					    ADM1025_REG_TEMP_HIGH(i));
+		}
+		data->alarms = i2c_smbus_read_byte_data(client,
+			       ADM1025_REG_STATUS1)
+			     | (i2c_smbus_read_byte_data(client,
+				ADM1025_REG_STATUS2) << 8);
+		data->vid = (i2c_smbus_read_byte_data(client,
+			     ADM1025_REG_VID) & 0x0f)
+			  | ((i2c_smbus_read_byte_data(client,
+			      ADM1025_REG_VID4) & 0x01) << 4);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[index],
+		       in_scale[index]));
+}
+
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[index],
+		       in_scale[index]));
+}
+
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[index],
+		       in_scale[index]));
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[index]));
+}
+
+static ssize_t
+show_temp_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[index]));
+}
+
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[index] = IN_TO_REG(val, in_scale[index]);
+	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(index),
+				  data->in_min[index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[index] = IN_TO_REG(val, in_scale[index]);
+	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index),
+				  data->in_max[index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define set_in(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+	show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+	show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+	show_in_max, set_in_max, offset)
+set_in(0);
+set_in(1);
+set_in(2);
+set_in(3);
+set_in(4);
+set_in(5);
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[index] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(index),
+				  data->temp_min[index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[index] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(index),
+				  data->temp_max[index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define set_temp(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+	show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+	show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+	show_temp_max, set_temp_max, offset - 1)
+set_temp(1);
+set_temp(2);
+
+static ssize_t
+show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t
+show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct adm1025_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+/*
+ * Real code
+ */
+
+static struct attribute *adm1025_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&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_in5_min.dev_attr.attr,
+	&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_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	NULL
+};
+
+static const struct attribute_group adm1025_group = {
+	.attrs = adm1025_attributes,
+};
+
+static struct attribute *adm1025_attributes_in4[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adm1025_group_in4 = {
+	.attrs = adm1025_attributes_in4,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1025_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	const char *name;
+	u8 man_id, chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Check for unused bits */
+	if ((i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG) & 0x80)
+	 || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0xC0)
+	 || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0xBC)) {
+		dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	/* Identification */
+	chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID);
+	if ((chip_id & 0xF0) != 0x20)
+		return -ENODEV;
+
+	man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID);
+	if (man_id == 0x41)
+		name = "adm1025";
+	else if (man_id == 0xA1 && client->addr != 0x2E)
+		name = "ne1619";
+	else
+		return -ENODEV;
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adm1025_init_client(struct i2c_client *client)
+{
+	u8 reg;
+	struct adm1025_data *data = i2c_get_clientdata(client);
+	int i;
+
+	data->vrm = vid_which_vrm();
+
+	/*
+	 * Set high limits
+	 * Usually we avoid setting limits on driver init, but it happens
+	 * that the ADM1025 comes with stupid default limits (all registers
+	 * set to 0). In case the chip has not gone through any limit
+	 * setting yet, we better set the high limits to the max so that
+	 * no alarm triggers.
+	 */
+	for (i = 0; i < 6; i++) {
+		reg = i2c_smbus_read_byte_data(client,
+					       ADM1025_REG_IN_MAX(i));
+		if (reg == 0)
+			i2c_smbus_write_byte_data(client,
+						  ADM1025_REG_IN_MAX(i),
+						  0xFF);
+	}
+	for (i = 0; i < 2; i++) {
+		reg = i2c_smbus_read_byte_data(client,
+					       ADM1025_REG_TEMP_HIGH(i));
+		if (reg == 0)
+			i2c_smbus_write_byte_data(client,
+						  ADM1025_REG_TEMP_HIGH(i),
+						  0x7F);
+	}
+
+	/*
+	 * Start the conversions
+	 */
+	reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
+	if (!(reg & 0x01))
+		i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG,
+					  (reg&0x7E)|0x01);
+}
+
+static int adm1025_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct adm1025_data *data;
+	u8 config;
+
+	data = devm_kzalloc(dev, sizeof(struct adm1025_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the ADM1025 chip */
+	adm1025_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &adm1025_group;
+	/* Pin 11 is either in4 (+12V) or VID4 */
+	config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
+	if (!(config & 0x20))
+		data->groups[1] = &adm1025_group_in4;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm1025_id[] = {
+	{ "adm1025", adm1025 },
+	{ "ne1619", ne1619 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1025_id);
+
+static struct i2c_driver adm1025_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adm1025",
+	},
+	.probe		= adm1025_probe,
+	.id_table	= adm1025_id,
+	.detect		= adm1025_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm1025_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("ADM1025 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
new file mode 100644
index 0000000..e67b9a5
--- /dev/null
+++ b/drivers/hwmon/adm1026.c
@@ -0,0 +1,1859 @@
+/*
+ * adm1026.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (C) 2002, 2003  Philip Pokorny <ppokorny@penguincomputing.com>
+ * Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
+ *
+ * Chip details at:
+ *
+ * <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026>
+ *
+ * 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/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+module_param_array(gpio_input, int, NULL, 0);
+MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
+module_param_array(gpio_output, int, NULL, 0);
+MODULE_PARM_DESC(gpio_output,
+		 "List of GPIO pins (0-16) to program as outputs");
+module_param_array(gpio_inverted, int, NULL, 0);
+MODULE_PARM_DESC(gpio_inverted,
+		 "List of GPIO pins (0-16) to program as inverted");
+module_param_array(gpio_normal, int, NULL, 0);
+MODULE_PARM_DESC(gpio_normal,
+		 "List of GPIO pins (0-16) to program as normal/non-inverted");
+module_param_array(gpio_fan, int, NULL, 0);
+MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
+
+/* Many ADM1026 constants specified below */
+
+/* The ADM1026 registers */
+#define ADM1026_REG_CONFIG1	0x00
+#define CFG1_MONITOR		0x01
+#define CFG1_INT_ENABLE		0x02
+#define CFG1_INT_CLEAR		0x04
+#define CFG1_AIN8_9		0x08
+#define CFG1_THERM_HOT		0x10
+#define CFG1_DAC_AFC		0x20
+#define CFG1_PWM_AFC		0x40
+#define CFG1_RESET		0x80
+
+#define ADM1026_REG_CONFIG2	0x01
+/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */
+
+#define ADM1026_REG_CONFIG3	0x07
+#define CFG3_GPIO16_ENABLE	0x01
+#define CFG3_CI_CLEAR		0x02
+#define CFG3_VREF_250		0x04
+#define CFG3_GPIO16_DIR		0x40
+#define CFG3_GPIO16_POL		0x80
+
+#define ADM1026_REG_E2CONFIG	0x13
+#define E2CFG_READ		0x01
+#define E2CFG_WRITE		0x02
+#define E2CFG_ERASE		0x04
+#define E2CFG_ROM		0x08
+#define E2CFG_CLK_EXT		0x80
+
+/*
+ * There are 10 general analog inputs and 7 dedicated inputs
+ * They are:
+ *    0 - 9  =  AIN0 - AIN9
+ *       10  =  Vbat
+ *       11  =  3.3V Standby
+ *       12  =  3.3V Main
+ *       13  =  +5V
+ *       14  =  Vccp (CPU core voltage)
+ *       15  =  +12V
+ *       16  =  -12V
+ */
+static u16 ADM1026_REG_IN[] = {
+		0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+		0x36, 0x37, 0x27, 0x29, 0x26, 0x2a,
+		0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+	};
+static u16 ADM1026_REG_IN_MIN[] = {
+		0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
+		0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a,
+		0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+	};
+static u16 ADM1026_REG_IN_MAX[] = {
+		0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+		0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42,
+		0x43, 0x44, 0x45, 0x46, 0x47
+	};
+
+/*
+ * Temperatures are:
+ *    0 - Internal
+ *    1 - External 1
+ *    2 - External 2
+ */
+static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 };
+static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 };
+static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 };
+static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 };
+static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f };
+static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
+
+#define ADM1026_REG_FAN(nr)		(0x38 + (nr))
+#define ADM1026_REG_FAN_MIN(nr)		(0x60 + (nr))
+#define ADM1026_REG_FAN_DIV_0_3		0x02
+#define ADM1026_REG_FAN_DIV_4_7		0x03
+
+#define ADM1026_REG_DAC			0x04
+#define ADM1026_REG_PWM			0x05
+
+#define ADM1026_REG_GPIO_CFG_0_3	0x08
+#define ADM1026_REG_GPIO_CFG_4_7	0x09
+#define ADM1026_REG_GPIO_CFG_8_11	0x0a
+#define ADM1026_REG_GPIO_CFG_12_15	0x0b
+/* CFG_16 in REG_CFG3 */
+#define ADM1026_REG_GPIO_STATUS_0_7	0x24
+#define ADM1026_REG_GPIO_STATUS_8_15	0x25
+/* STATUS_16 in REG_STATUS4 */
+#define ADM1026_REG_GPIO_MASK_0_7	0x1c
+#define ADM1026_REG_GPIO_MASK_8_15	0x1d
+/* MASK_16 in REG_MASK4 */
+
+#define ADM1026_REG_COMPANY		0x16
+#define ADM1026_REG_VERSTEP		0x17
+/* These are the recognized values for the above regs */
+#define ADM1026_COMPANY_ANALOG_DEV	0x41
+#define ADM1026_VERSTEP_GENERIC		0x40
+#define ADM1026_VERSTEP_ADM1026		0x44
+
+#define ADM1026_REG_MASK1		0x18
+#define ADM1026_REG_MASK2		0x19
+#define ADM1026_REG_MASK3		0x1a
+#define ADM1026_REG_MASK4		0x1b
+
+#define ADM1026_REG_STATUS1		0x20
+#define ADM1026_REG_STATUS2		0x21
+#define ADM1026_REG_STATUS3		0x22
+#define ADM1026_REG_STATUS4		0x23
+
+#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6
+#define ADM1026_FAN_CONTROL_TEMP_RANGE	20
+#define ADM1026_PWM_MAX			255
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ */
+
+/*
+ * IN are scaled according to built-in resistors.  These are the
+ *   voltages corresponding to 3/4 of full scale (192 or 0xc0)
+ *   NOTE: The -12V input needs an additional factor to account
+ *      for the Vref pullup resistor.
+ *      NEG12_OFFSET = SCALE * Vref / V-192 - Vref
+ *                   = 13875 * 2.50 / 1.875 - 2500
+ *                   = 16000
+ *
+ * The values in this table are based on Table II, page 15 of the
+ *    datasheet.
+ */
+static int adm1026_scaling[] = { /* .001 Volts */
+		2250, 2250, 2250, 2250, 2250, 2250,
+		1875, 1875, 1875, 1875, 3000, 3330,
+		3330, 4995, 2250, 12000, 13875
+	};
+#define NEG12_OFFSET  16000
+#define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
+#define INS_TO_REG(n, val)  (clamp_val(SCALE(val, adm1026_scaling[n], 192),\
+	0, 255))
+#define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
+
+/*
+ * FAN speed is measured using 22.5kHz clock and counts for 2 pulses
+ *   and we assume a 2 pulse-per-rev fan tach signal
+ *      22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
+ */
+#define FAN_TO_REG(val, div)  ((val) <= 0 ? 0xff : \
+				clamp_val(1350000 / ((val) * (div)), \
+					      1, 254))
+#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
+				1350000 / ((val) * (div)))
+#define DIV_FROM_REG(val) (1 << (val))
+#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
+
+/* Temperature is reported in 1 degC increments */
+#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
+					/ 1000, -127, 127))
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
+					  / 1000, -127, 127))
+#define OFFSET_FROM_REG(val) ((val) * 1000)
+
+#define PWM_TO_REG(val) (clamp_val(val, 0, 255))
+#define PWM_FROM_REG(val) (val)
+
+#define PWM_MIN_TO_REG(val) ((val) & 0xf0)
+#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4))
+
+/*
+ * Analog output is a voltage, and scaled to millivolts.  The datasheet
+ *   indicates that the DAC could be used to drive the fans, but in our
+ *   example board (Arima HDAMA) it isn't connected to the fans at all.
+ */
+#define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255))
+#define DAC_FROM_REG(val) (((val) * 2500) / 255)
+
+/*
+ * Chip sampling rates
+ *
+ * Some sensors are not updated more frequently than once per second
+ *    so it doesn't make sense to read them more often than that.
+ *    We cache the results and return the saved data if the driver
+ *    is called again before a second has elapsed.
+ *
+ * Also, there is significant configuration data for this chip
+ *    So, we keep the config data up to date in the cache
+ *    when it is written and only sample it once every 5 *minutes*
+ */
+#define ADM1026_DATA_INTERVAL		(1 * HZ)
+#define ADM1026_CONFIG_INTERVAL		(5 * 60 * HZ)
+
+/*
+ * We allow for multiple chips in a single system.
+ *
+ * For each registered ADM1026, we need to keep state information
+ * at client->data. The adm1026_data structure is dynamically
+ * allocated, when a new client structure is allocated.
+ */
+
+struct pwm_data {
+	u8 pwm;
+	u8 enable;
+	u8 auto_pwm_min;
+};
+
+struct adm1026_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+
+	struct mutex update_lock;
+	int valid;		/* !=0 if following fields are valid */
+	unsigned long last_reading;	/* In jiffies */
+	unsigned long last_config;	/* In jiffies */
+
+	u8 in[17];		/* Register value */
+	u8 in_max[17];		/* Register value */
+	u8 in_min[17];		/* Register value */
+	s8 temp[3];		/* Register value */
+	s8 temp_min[3];		/* Register value */
+	s8 temp_max[3];		/* Register value */
+	s8 temp_tmin[3];	/* Register value */
+	s8 temp_crit[3];	/* Register value */
+	s8 temp_offset[3];	/* Register value */
+	u8 fan[8];		/* Register value */
+	u8 fan_min[8];		/* Register value */
+	u8 fan_div[8];		/* Decoded value */
+	struct pwm_data pwm1;	/* Pwm control values */
+	u8 vrm;			/* VRM version */
+	u8 analog_out;		/* Register value (DAC) */
+	long alarms;		/* Register encoding, combined */
+	long alarm_mask;	/* Register encoding, combined */
+	long gpio;		/* Register encoding, combined */
+	long gpio_mask;		/* Register encoding, combined */
+	u8 gpio_config[17];	/* Decoded value */
+	u8 config1;		/* Register value */
+	u8 config2;		/* Register value */
+	u8 config3;		/* Register value */
+};
+
+static int adm1026_read_value(struct i2c_client *client, u8 reg)
+{
+	int res;
+
+	if (reg < 0x80) {
+		/* "RAM" locations */
+		res = i2c_smbus_read_byte_data(client, reg) & 0xff;
+	} else {
+		/* EEPROM, do nothing */
+		res = 0;
+	}
+	return res;
+}
+
+static int adm1026_write_value(struct i2c_client *client, u8 reg, int value)
+{
+	int res;
+
+	if (reg < 0x80) {
+		/* "RAM" locations */
+		res = i2c_smbus_write_byte_data(client, reg, value);
+	} else {
+		/* EEPROM, do nothing */
+		res = 0;
+	}
+	return res;
+}
+
+static struct adm1026_data *adm1026_update_device(struct device *dev)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+	long value, alarms, gpio;
+
+	mutex_lock(&data->update_lock);
+	if (!data->valid
+	    || time_after(jiffies,
+			  data->last_reading + ADM1026_DATA_INTERVAL)) {
+		/* Things that change quickly */
+		dev_dbg(&client->dev, "Reading sensor values\n");
+		for (i = 0; i <= 16; ++i) {
+			data->in[i] =
+			    adm1026_read_value(client, ADM1026_REG_IN[i]);
+		}
+
+		for (i = 0; i <= 7; ++i) {
+			data->fan[i] =
+			    adm1026_read_value(client, ADM1026_REG_FAN(i));
+		}
+
+		for (i = 0; i <= 2; ++i) {
+			/*
+			 * NOTE: temp[] is s8 and we assume 2's complement
+			 *   "conversion" in the assignment
+			 */
+			data->temp[i] =
+			    adm1026_read_value(client, ADM1026_REG_TEMP[i]);
+		}
+
+		data->pwm1.pwm = adm1026_read_value(client,
+			ADM1026_REG_PWM);
+		data->analog_out = adm1026_read_value(client,
+			ADM1026_REG_DAC);
+		/* GPIO16 is MSbit of alarms, move it to gpio */
+		alarms = adm1026_read_value(client, ADM1026_REG_STATUS4);
+		gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
+		alarms &= 0x7f;
+		alarms <<= 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3);
+		alarms <<= 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2);
+		alarms <<= 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1);
+		data->alarms = alarms;
+
+		/* Read the GPIO values */
+		gpio |= adm1026_read_value(client,
+			ADM1026_REG_GPIO_STATUS_8_15);
+		gpio <<= 8;
+		gpio |= adm1026_read_value(client,
+			ADM1026_REG_GPIO_STATUS_0_7);
+		data->gpio = gpio;
+
+		data->last_reading = jiffies;
+	}	/* last_reading */
+
+	if (!data->valid ||
+	    time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) {
+		/* Things that don't change often */
+		dev_dbg(&client->dev, "Reading config values\n");
+		for (i = 0; i <= 16; ++i) {
+			data->in_min[i] = adm1026_read_value(client,
+				ADM1026_REG_IN_MIN[i]);
+			data->in_max[i] = adm1026_read_value(client,
+				ADM1026_REG_IN_MAX[i]);
+		}
+
+		value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3)
+			| (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7)
+			<< 8);
+		for (i = 0; i <= 7; ++i) {
+			data->fan_min[i] = adm1026_read_value(client,
+				ADM1026_REG_FAN_MIN(i));
+			data->fan_div[i] = DIV_FROM_REG(value & 0x03);
+			value >>= 2;
+		}
+
+		for (i = 0; i <= 2; ++i) {
+			/*
+			 * NOTE: temp_xxx[] are s8 and we assume 2's
+			 *    complement "conversion" in the assignment
+			 */
+			data->temp_min[i] = adm1026_read_value(client,
+				ADM1026_REG_TEMP_MIN[i]);
+			data->temp_max[i] = adm1026_read_value(client,
+				ADM1026_REG_TEMP_MAX[i]);
+			data->temp_tmin[i] = adm1026_read_value(client,
+				ADM1026_REG_TEMP_TMIN[i]);
+			data->temp_crit[i] = adm1026_read_value(client,
+				ADM1026_REG_TEMP_THERM[i]);
+			data->temp_offset[i] = adm1026_read_value(client,
+				ADM1026_REG_TEMP_OFFSET[i]);
+		}
+
+		/* Read the STATUS/alarm masks */
+		alarms = adm1026_read_value(client, ADM1026_REG_MASK4);
+		gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
+		alarms = (alarms & 0x7f) << 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_MASK3);
+		alarms <<= 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_MASK2);
+		alarms <<= 8;
+		alarms |= adm1026_read_value(client, ADM1026_REG_MASK1);
+		data->alarm_mask = alarms;
+
+		/* Read the GPIO values */
+		gpio |= adm1026_read_value(client,
+			ADM1026_REG_GPIO_MASK_8_15);
+		gpio <<= 8;
+		gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7);
+		data->gpio_mask = gpio;
+
+		/* Read various values from CONFIG1 */
+		data->config1 = adm1026_read_value(client,
+			ADM1026_REG_CONFIG1);
+		if (data->config1 & CFG1_PWM_AFC) {
+			data->pwm1.enable = 2;
+			data->pwm1.auto_pwm_min =
+				PWM_MIN_FROM_REG(data->pwm1.pwm);
+		}
+		/* Read the GPIO config */
+		data->config2 = adm1026_read_value(client,
+			ADM1026_REG_CONFIG2);
+		data->config3 = adm1026_read_value(client,
+			ADM1026_REG_CONFIG3);
+		data->gpio_config[16] = (data->config3 >> 6) & 0x03;
+
+		value = 0;
+		for (i = 0; i <= 15; ++i) {
+			if ((i & 0x03) == 0) {
+				value = adm1026_read_value(client,
+					    ADM1026_REG_GPIO_CFG_0_3 + i/4);
+			}
+			data->gpio_config[i] = value & 0x03;
+			value >>= 2;
+		}
+
+		data->last_config = jiffies;
+	}	/* last_config */
+
+	data->valid = 1;
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in[nr]));
+}
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr]));
+}
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = INS_TO_REG(nr, val);
+	adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr]));
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = INS_TO_REG(nr, val);
+	adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define in_reg(offset)						\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,	\
+		NULL, offset);					\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
+
+
+in_reg(0);
+in_reg(1);
+in_reg(2);
+in_reg(3);
+in_reg(4);
+in_reg(5);
+in_reg(6);
+in_reg(7);
+in_reg(8);
+in_reg(9);
+in_reg(10);
+in_reg(11);
+in_reg(12);
+in_reg(13);
+in_reg(14);
+in_reg(15);
+
+static ssize_t show_in16(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in[16]) -
+		NEG12_OFFSET);
+}
+static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_min[16])
+		- NEG12_OFFSET);
+}
+static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
+	adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_max[16])
+			- NEG12_OFFSET);
+}
+static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
+	adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16);
+static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min,
+			  set_in16_min, 16);
+static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max,
+			  set_in16_max, 16);
+
+
+/* Now add fan read/write functions */
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		data->fan_div[nr]));
+}
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+		data->fan_div[nr]));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]);
+	adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr),
+		data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define fan_offset(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL,	\
+		offset - 1);						\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);
+
+fan_offset(1);
+fan_offset(2);
+fan_offset(3);
+fan_offset(4);
+fan_offset(5);
+fan_offset(6);
+fan_offset(7);
+fan_offset(8);
+
+/* Adjust fan_min to account for new fan divisor */
+static void fixup_fan_min(struct device *dev, int fan, int old_div)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int new_min;
+	int new_div = data->fan_div[fan];
+
+	/* 0 and 0xff are special.  Don't adjust them */
+	if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff)
+		return;
+
+	new_min = data->fan_min[fan] * old_div / new_div;
+	new_min = clamp_val(new_min, 1, 254);
+	data->fan_min[fan] = new_min;
+	adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
+}
+
+/* Now add fan_div read/write functions */
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", data->fan_div[nr]);
+}
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int orig_div, new_div;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	new_div = DIV_TO_REG(val);
+
+	mutex_lock(&data->update_lock);
+	orig_div = data->fan_div[nr];
+	data->fan_div[nr] = DIV_FROM_REG(new_div);
+
+	if (nr < 4) { /* 0 <= nr < 4 */
+		adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
+				    (DIV_TO_REG(data->fan_div[0]) << 0) |
+				    (DIV_TO_REG(data->fan_div[1]) << 2) |
+				    (DIV_TO_REG(data->fan_div[2]) << 4) |
+				    (DIV_TO_REG(data->fan_div[3]) << 6));
+	} else { /* 3 < nr < 8 */
+		adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
+				    (DIV_TO_REG(data->fan_div[4]) << 0) |
+				    (DIV_TO_REG(data->fan_div[5]) << 2) |
+				    (DIV_TO_REG(data->fan_div[6]) << 4) |
+				    (DIV_TO_REG(data->fan_div[7]) << 6));
+	}
+
+	if (data->fan_div[nr] != orig_div)
+		fixup_fan_min(dev, nr, orig_div);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define fan_offset_div(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);
+
+fan_offset_div(1);
+fan_offset_div(2);
+fan_offset_div(3);
+fan_offset_div(4);
+fan_offset_div(5);
+fan_offset_div(6);
+fan_offset_div(7);
+fan_offset_div(8);
+
+/* Temps */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = TEMP_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr],
+		data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = TEMP_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr],
+		data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,	\
+		NULL, offset - 1);					\
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_temp_min, set_temp_min, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_max, set_temp_max, offset - 1);
+
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+static ssize_t show_temp_offset(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
+}
+static ssize_t set_temp_offset(struct device *dev,
+		struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_offset[nr] = TEMP_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr],
+		data->temp_offset[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_offset_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR,	\
+		show_temp_offset, set_temp_offset, offset - 1);
+
+temp_offset_reg(1);
+temp_offset_reg(2);
+temp_offset_reg(3);
+
+static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(
+		ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr]));
+}
+static ssize_t show_temp_auto_point2_temp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr] +
+		ADM1026_FAN_CONTROL_TEMP_RANGE));
+}
+static ssize_t show_temp_auto_point1_temp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr]));
+}
+static ssize_t set_temp_auto_point1_temp(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_tmin[nr] = TEMP_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr],
+		data->temp_tmin[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_auto_point(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp,		\
+		S_IRUGO | S_IWUSR, show_temp_auto_point1_temp,		\
+		set_temp_auto_point1_temp, offset - 1);			\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO,\
+		show_temp_auto_point1_temp_hyst, NULL, offset - 1);	\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO,	\
+		show_temp_auto_point2_temp, NULL, offset - 1);
+
+temp_auto_point(1);
+temp_auto_point(2);
+temp_auto_point(3);
+
+static ssize_t show_temp_crit_enable(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", (data->config1 & CFG1_THERM_HOT) >> 4);
+}
+static ssize_t set_temp_crit_enable(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
+	adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define temp_crit_enable(offset)				\
+static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \
+	show_temp_crit_enable, set_temp_crit_enable);
+
+temp_crit_enable(1);
+temp_crit_enable(2);
+temp_crit_enable(3);
+
+static ssize_t show_temp_crit(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
+}
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_crit[nr] = TEMP_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr],
+		data->temp_crit[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_crit_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR,	\
+		show_temp_crit, set_temp_crit, offset - 1);
+
+temp_crit_reg(1);
+temp_crit_reg(2);
+temp_crit_reg(3);
+
+static ssize_t show_analog_out_reg(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out));
+}
+static ssize_t set_analog_out_reg(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->analog_out = DAC_TO_REG(val);
+	adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg,
+	set_analog_out_reg);
+
+static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	int vid = (data->gpio >> 11) & 0x1f;
+
+	dev_dbg(dev, "Setting VID from GPIO11-15.\n");
+	return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t show_alarms_reg(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%ld\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%ld\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in15_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in16_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_alarm, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26);
+
+static ssize_t show_alarm_mask(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%ld\n", data->alarm_mask);
+}
+static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long mask;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->alarm_mask = val & 0x7fffffff;
+	mask = data->alarm_mask
+		| (data->gpio_mask & 0x10000 ? 0x80000000 : 0);
+	adm1026_write_value(client, ADM1026_REG_MASK1,
+		mask & 0xff);
+	mask >>= 8;
+	adm1026_write_value(client, ADM1026_REG_MASK2,
+		mask & 0xff);
+	mask >>= 8;
+	adm1026_write_value(client, ADM1026_REG_MASK3,
+		mask & 0xff);
+	mask >>= 8;
+	adm1026_write_value(client, ADM1026_REG_MASK4,
+		mask & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask,
+	set_alarm_mask);
+
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%ld\n", data->gpio);
+}
+static ssize_t set_gpio(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long gpio;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->gpio = val & 0x1ffff;
+	gpio = data->gpio;
+	adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7, gpio & 0xff);
+	gpio >>= 8;
+	adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15, gpio & 0xff);
+	gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f);
+	adm1026_write_value(client, ADM1026_REG_STATUS4, gpio & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio);
+
+static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%ld\n", data->gpio_mask);
+}
+static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long mask;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->gpio_mask = val & 0x1ffff;
+	mask = data->gpio_mask;
+	adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, mask & 0xff);
+	mask >>= 8;
+	adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, mask & 0xff);
+	mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f);
+	adm1026_write_value(client, ADM1026_REG_MASK1, mask & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask);
+
+static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm));
+}
+
+static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	if (data->pwm1.enable == 1) {
+		long val;
+		int err;
+
+		err = kstrtol(buf, 10, &val);
+		if (err)
+			return err;
+
+		mutex_lock(&data->update_lock);
+		data->pwm1.pwm = PWM_TO_REG(val);
+		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+		mutex_unlock(&data->update_lock);
+	}
+	return count;
+}
+
+static ssize_t show_auto_pwm_min(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min);
+}
+
+static ssize_t set_auto_pwm_min(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1.auto_pwm_min = clamp_val(val, 0, 255);
+	if (data->pwm1.enable == 2) { /* apply immediately */
+		data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
+			PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
+		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_auto_pwm_max(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", ADM1026_PWM_MAX);
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct adm1026_data *data = adm1026_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1.enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct adm1026_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int old_enable;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val >= 3)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	old_enable = data->pwm1.enable;
+	data->pwm1.enable = val;
+	data->config1 = (data->config1 & ~CFG1_PWM_AFC)
+			| ((val == 2) ? CFG1_PWM_AFC : 0);
+	adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1);
+	if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */
+		data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
+			PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
+		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+	} else if (!((old_enable == 1) && (val == 1))) {
+		/* set pwm to safe value */
+		data->pwm1.pwm = 255;
+		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* enable PWM fan control */
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+	set_pwm_enable);
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+	set_pwm_enable);
+static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+	set_pwm_enable);
+static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR,
+	show_auto_pwm_min, set_auto_pwm_min);
+static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR,
+	show_auto_pwm_min, set_auto_pwm_min);
+static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR,
+	show_auto_pwm_min, set_auto_pwm_min);
+
+static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+
+static struct attribute *adm1026_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in10_max.dev_attr.attr,
+	&sensor_dev_attr_in10_min.dev_attr.attr,
+	&sensor_dev_attr_in10_alarm.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in11_max.dev_attr.attr,
+	&sensor_dev_attr_in11_min.dev_attr.attr,
+	&sensor_dev_attr_in11_alarm.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in12_max.dev_attr.attr,
+	&sensor_dev_attr_in12_min.dev_attr.attr,
+	&sensor_dev_attr_in12_alarm.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+	&sensor_dev_attr_in13_max.dev_attr.attr,
+	&sensor_dev_attr_in13_min.dev_attr.attr,
+	&sensor_dev_attr_in13_alarm.dev_attr.attr,
+	&sensor_dev_attr_in14_input.dev_attr.attr,
+	&sensor_dev_attr_in14_max.dev_attr.attr,
+	&sensor_dev_attr_in14_min.dev_attr.attr,
+	&sensor_dev_attr_in14_alarm.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	&sensor_dev_attr_in15_max.dev_attr.attr,
+	&sensor_dev_attr_in15_min.dev_attr.attr,
+	&sensor_dev_attr_in15_alarm.dev_attr.attr,
+	&sensor_dev_attr_in16_input.dev_attr.attr,
+	&sensor_dev_attr_in16_max.dev_attr.attr,
+	&sensor_dev_attr_in16_min.dev_attr.attr,
+	&sensor_dev_attr_in16_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_div.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_div.dev_attr.attr,
+	&sensor_dev_attr_fan5_min.dev_attr.attr,
+	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_div.dev_attr.attr,
+	&sensor_dev_attr_fan6_min.dev_attr.attr,
+	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan7_input.dev_attr.attr,
+	&sensor_dev_attr_fan7_div.dev_attr.attr,
+	&sensor_dev_attr_fan7_min.dev_attr.attr,
+	&sensor_dev_attr_fan7_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan8_input.dev_attr.attr,
+	&sensor_dev_attr_fan8_div.dev_attr.attr,
+	&sensor_dev_attr_fan8_min.dev_attr.attr,
+	&sensor_dev_attr_fan8_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&dev_attr_temp1_crit_enable.attr,
+	&dev_attr_temp2_crit_enable.attr,
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_alarm_mask.attr,
+	&dev_attr_gpio.attr,
+	&dev_attr_gpio_mask.attr,
+	&dev_attr_pwm1.attr,
+	&dev_attr_pwm2.attr,
+	&dev_attr_pwm3.attr,
+	&dev_attr_pwm1_enable.attr,
+	&dev_attr_pwm2_enable.attr,
+	&dev_attr_pwm3_enable.attr,
+	&dev_attr_temp1_auto_point1_pwm.attr,
+	&dev_attr_temp2_auto_point1_pwm.attr,
+	&dev_attr_temp1_auto_point2_pwm.attr,
+	&dev_attr_temp2_auto_point2_pwm.attr,
+	&dev_attr_analog_out.attr,
+	NULL
+};
+
+static const struct attribute_group adm1026_group = {
+	.attrs = adm1026_attributes,
+};
+
+static struct attribute *adm1026_attributes_temp3[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&dev_attr_temp3_crit_enable.attr,
+	&dev_attr_temp3_auto_point1_pwm.attr,
+	&dev_attr_temp3_auto_point2_pwm.attr,
+	NULL
+};
+
+static const struct attribute_group adm1026_group_temp3 = {
+	.attrs = adm1026_attributes_temp3,
+};
+
+static struct attribute *adm1026_attributes_in8_9[] = {
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in8_max.dev_attr.attr,
+	&sensor_dev_attr_in8_min.dev_attr.attr,
+	&sensor_dev_attr_in8_alarm.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in9_max.dev_attr.attr,
+	&sensor_dev_attr_in9_min.dev_attr.attr,
+	&sensor_dev_attr_in9_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adm1026_group_in8_9 = {
+	.attrs = adm1026_attributes_in8_9,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1026_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	int company, verstep;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		/* We need to be able to do byte I/O */
+		return -ENODEV;
+	}
+
+	/* Now, we do the remaining detection. */
+
+	company = adm1026_read_value(client, ADM1026_REG_COMPANY);
+	verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
+
+	dev_dbg(&adapter->dev,
+		"Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+		i2c_adapter_id(client->adapter), client->addr,
+		company, verstep);
+
+	/* Determine the chip type. */
+	dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x...\n",
+		i2c_adapter_id(adapter), address);
+	if (company == ADM1026_COMPANY_ANALOG_DEV
+	    && verstep == ADM1026_VERSTEP_ADM1026) {
+		/* Analog Devices ADM1026 */
+	} else if (company == ADM1026_COMPANY_ANALOG_DEV
+		&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+		dev_err(&adapter->dev,
+			"Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
+			verstep);
+	} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+		dev_err(&adapter->dev,
+			"Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
+			verstep);
+	} else {
+		dev_dbg(&adapter->dev, "Autodetection failed\n");
+		/* Not an ADM1026... */
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "adm1026", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adm1026_print_gpio(struct i2c_client *client)
+{
+	struct adm1026_data *data = i2c_get_clientdata(client);
+	int i;
+
+	dev_dbg(&client->dev, "GPIO config is:\n");
+	for (i = 0; i <= 7; ++i) {
+		if (data->config2 & (1 << i)) {
+			dev_dbg(&client->dev, "\t%sGP%s%d\n",
+				data->gpio_config[i] & 0x02 ? "" : "!",
+				data->gpio_config[i] & 0x01 ? "OUT" : "IN",
+				i);
+		} else {
+			dev_dbg(&client->dev, "\tFAN%d\n", i);
+		}
+	}
+	for (i = 8; i <= 15; ++i) {
+		dev_dbg(&client->dev, "\t%sGP%s%d\n",
+			data->gpio_config[i] & 0x02 ? "" : "!",
+			data->gpio_config[i] & 0x01 ? "OUT" : "IN",
+			i);
+	}
+	if (data->config3 & CFG3_GPIO16_ENABLE) {
+		dev_dbg(&client->dev, "\t%sGP%s16\n",
+			data->gpio_config[16] & 0x02 ? "" : "!",
+			data->gpio_config[16] & 0x01 ? "OUT" : "IN");
+	} else {
+		/* GPIO16 is THERM */
+		dev_dbg(&client->dev, "\tTHERM\n");
+	}
+}
+
+static void adm1026_fixup_gpio(struct i2c_client *client)
+{
+	struct adm1026_data *data = i2c_get_clientdata(client);
+	int i;
+	int value;
+
+	/* Make the changes requested. */
+	/*
+	 * We may need to unlock/stop monitoring or soft-reset the
+	 *    chip before we can make changes.  This hasn't been
+	 *    tested much.  FIXME
+	 */
+
+	/* Make outputs */
+	for (i = 0; i <= 16; ++i) {
+		if (gpio_output[i] >= 0 && gpio_output[i] <= 16)
+			data->gpio_config[gpio_output[i]] |= 0x01;
+		/* if GPIO0-7 is output, it isn't a FAN tach */
+		if (gpio_output[i] >= 0 && gpio_output[i] <= 7)
+			data->config2 |= 1 << gpio_output[i];
+	}
+
+	/* Input overrides output */
+	for (i = 0; i <= 16; ++i) {
+		if (gpio_input[i] >= 0 && gpio_input[i] <= 16)
+			data->gpio_config[gpio_input[i]] &= ~0x01;
+		/* if GPIO0-7 is input, it isn't a FAN tach */
+		if (gpio_input[i] >= 0 && gpio_input[i] <= 7)
+			data->config2 |= 1 << gpio_input[i];
+	}
+
+	/* Inverted */
+	for (i = 0; i <= 16; ++i) {
+		if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16)
+			data->gpio_config[gpio_inverted[i]] &= ~0x02;
+	}
+
+	/* Normal overrides inverted */
+	for (i = 0; i <= 16; ++i) {
+		if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16)
+			data->gpio_config[gpio_normal[i]] |= 0x02;
+	}
+
+	/* Fan overrides input and output */
+	for (i = 0; i <= 7; ++i) {
+		if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7)
+			data->config2 &= ~(1 << gpio_fan[i]);
+	}
+
+	/* Write new configs to registers */
+	adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
+	data->config3 = (data->config3 & 0x3f)
+			| ((data->gpio_config[16] & 0x03) << 6);
+	adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3);
+	for (i = 15, value = 0; i >= 0; --i) {
+		value <<= 2;
+		value |= data->gpio_config[i] & 0x03;
+		if ((i & 0x03) == 0) {
+			adm1026_write_value(client,
+					ADM1026_REG_GPIO_CFG_0_3 + i/4,
+					value);
+			value = 0;
+		}
+	}
+
+	/* Print the new config */
+	adm1026_print_gpio(client);
+}
+
+static void adm1026_init_client(struct i2c_client *client)
+{
+	int value, i;
+	struct adm1026_data *data = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "Initializing device\n");
+	/* Read chip config */
+	data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
+	data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
+	data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
+
+	/* Inform user of chip config */
+	dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
+		data->config1);
+	if ((data->config1 & CFG1_MONITOR) == 0) {
+		dev_dbg(&client->dev,
+			"Monitoring not currently enabled.\n");
+	}
+	if (data->config1 & CFG1_INT_ENABLE) {
+		dev_dbg(&client->dev,
+			"SMBALERT interrupts are enabled.\n");
+	}
+	if (data->config1 & CFG1_AIN8_9) {
+		dev_dbg(&client->dev,
+			"in8 and in9 enabled. temp3 disabled.\n");
+	} else {
+		dev_dbg(&client->dev,
+			"temp3 enabled.  in8 and in9 disabled.\n");
+	}
+	if (data->config1 & CFG1_THERM_HOT) {
+		dev_dbg(&client->dev,
+			"Automatic THERM, PWM, and temp limits enabled.\n");
+	}
+
+	if (data->config3 & CFG3_GPIO16_ENABLE) {
+		dev_dbg(&client->dev,
+			"GPIO16 enabled.  THERM pin disabled.\n");
+	} else {
+		dev_dbg(&client->dev,
+			"THERM pin enabled.  GPIO16 disabled.\n");
+	}
+	if (data->config3 & CFG3_VREF_250)
+		dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
+	else
+		dev_dbg(&client->dev, "Vref is 1.82 Volts.\n");
+	/* Read and pick apart the existing GPIO configuration */
+	value = 0;
+	for (i = 0; i <= 15; ++i) {
+		if ((i & 0x03) == 0) {
+			value = adm1026_read_value(client,
+					ADM1026_REG_GPIO_CFG_0_3 + i / 4);
+		}
+		data->gpio_config[i] = value & 0x03;
+		value >>= 2;
+	}
+	data->gpio_config[16] = (data->config3 >> 6) & 0x03;
+
+	/* ... and then print it */
+	adm1026_print_gpio(client);
+
+	/*
+	 * If the user asks us to reprogram the GPIO config, then
+	 * do it now.
+	 */
+	if (gpio_input[0] != -1 || gpio_output[0] != -1
+		|| gpio_inverted[0] != -1 || gpio_normal[0] != -1
+		|| gpio_fan[0] != -1) {
+		adm1026_fixup_gpio(client);
+	}
+
+	/*
+	 * WE INTENTIONALLY make no changes to the limits,
+	 *   offsets, pwms, fans and zones.  If they were
+	 *   configured, we don't want to mess with them.
+	 *   If they weren't, the default is 100% PWM, no
+	 *   control and will suffice until 'sensors -s'
+	 *   can be run by the user.  We DO set the default
+	 *   value for pwm1.auto_pwm_min to its maximum
+	 *   so that enabling automatic pwm fan control
+	 *   without first setting a value for pwm1.auto_pwm_min
+	 *   will not result in potentially dangerous fan speed decrease.
+	 */
+	data->pwm1.auto_pwm_min = 255;
+	/* Start monitoring */
+	value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
+	/* Set MONITOR, clear interrupt acknowledge and s/w reset */
+	value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET);
+	dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value);
+	data->config1 = value;
+	adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
+
+	/* initialize fan_div[] to hardware defaults */
+	value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) |
+		(adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8);
+	for (i = 0; i <= 7; ++i) {
+		data->fan_div[i] = DIV_FROM_REG(value & 0x03);
+		value >>= 2;
+	}
+}
+
+static int adm1026_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct adm1026_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct adm1026_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Set the VRM version */
+	data->vrm = vid_which_vrm();
+
+	/* Initialize the ADM1026 chip */
+	adm1026_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &adm1026_group;
+	if (data->config1 & CFG1_AIN8_9)
+		data->groups[1] = &adm1026_group_in8_9;
+	else
+		data->groups[1] = &adm1026_group_temp3;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm1026_id[] = {
+	{ "adm1026", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1026_id);
+
+static struct i2c_driver adm1026_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adm1026",
+	},
+	.probe		= adm1026_probe,
+	.id_table	= adm1026_id,
+	.detect		= adm1026_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm1026_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
+	      "Justin Thiessen <jthiessen@penguincomputing.com>");
+MODULE_DESCRIPTION("ADM1026 driver");
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
new file mode 100644
index 0000000..8c5cdb5
--- /dev/null
+++ b/drivers/hwmon/adm1029.c
@@ -0,0 +1,417 @@
+/*
+ * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ *
+ * Copyright (C) 2006 Corentin LABBE <clabbe.montjoie@gmail.com>
+ *
+ * Based on LM83 Driver by Jean Delvare <jdelvare@suse.de>
+ *
+ * Give only processor, motherboard temperatures and fan tachs
+ * Very rare chip please let me know if you use it
+ *
+ * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.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 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., 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-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ */
+
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+						0x2e, 0x2f, I2C_CLIENT_END
+};
+
+/*
+ * The ADM1029 registers
+ * Manufacturer ID is 0x41 for Analog Devices
+ */
+
+#define ADM1029_REG_MAN_ID			0x0D
+#define ADM1029_REG_CHIP_ID			0x0E
+#define ADM1029_REG_CONFIG			0x01
+#define ADM1029_REG_NB_FAN_SUPPORT		0x02
+
+#define ADM1029_REG_TEMP_DEVICES_INSTALLED	0x06
+
+#define ADM1029_REG_LOCAL_TEMP			0xA0
+#define ADM1029_REG_REMOTE1_TEMP		0xA1
+#define ADM1029_REG_REMOTE2_TEMP		0xA2
+
+#define ADM1029_REG_LOCAL_TEMP_HIGH		0x90
+#define ADM1029_REG_REMOTE1_TEMP_HIGH		0x91
+#define ADM1029_REG_REMOTE2_TEMP_HIGH		0x92
+
+#define ADM1029_REG_LOCAL_TEMP_LOW		0x98
+#define ADM1029_REG_REMOTE1_TEMP_LOW		0x99
+#define ADM1029_REG_REMOTE2_TEMP_LOW		0x9A
+
+#define ADM1029_REG_FAN1			0x70
+#define ADM1029_REG_FAN2			0x71
+
+#define ADM1029_REG_FAN1_MIN			0x78
+#define ADM1029_REG_FAN2_MIN			0x79
+
+#define ADM1029_REG_FAN1_CONFIG			0x68
+#define ADM1029_REG_FAN2_CONFIG			0x69
+
+#define TEMP_FROM_REG(val)	((val) * 1000)
+
+#define DIV_FROM_REG(val)	(1 << (((val) >> 6) - 1))
+
+/* Registers to be checked by adm1029_update_device() */
+static const u8 ADM1029_REG_TEMP[] = {
+	ADM1029_REG_LOCAL_TEMP,
+	ADM1029_REG_REMOTE1_TEMP,
+	ADM1029_REG_REMOTE2_TEMP,
+	ADM1029_REG_LOCAL_TEMP_HIGH,
+	ADM1029_REG_REMOTE1_TEMP_HIGH,
+	ADM1029_REG_REMOTE2_TEMP_HIGH,
+	ADM1029_REG_LOCAL_TEMP_LOW,
+	ADM1029_REG_REMOTE1_TEMP_LOW,
+	ADM1029_REG_REMOTE2_TEMP_LOW,
+};
+
+static const u8 ADM1029_REG_FAN[] = {
+	ADM1029_REG_FAN1,
+	ADM1029_REG_FAN2,
+	ADM1029_REG_FAN1_MIN,
+	ADM1029_REG_FAN2_MIN,
+};
+
+static const u8 ADM1029_REG_FAN_DIV[] = {
+	ADM1029_REG_FAN1_CONFIG,
+	ADM1029_REG_FAN2_CONFIG,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct adm1029_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;		/* zero until following fields are valid */
+	unsigned long last_updated;	/* in jiffies */
+
+	/* registers values, signed for temperature, unsigned for other stuff */
+	s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];
+	u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];
+	u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
+};
+
+/*
+ * function that update the status of the chips (temperature for example)
+ */
+static struct adm1029_data *adm1029_update_device(struct device *dev)
+{
+	struct adm1029_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+	/*
+	 * Use the "cache" Luke, don't recheck values
+	 * if there are already checked not a long time later
+	 */
+	if (time_after(jiffies, data->last_updated + HZ * 2)
+	 || !data->valid) {
+		int nr;
+
+		dev_dbg(&client->dev, "Updating adm1029 data\n");
+
+		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
+			data->temp[nr] =
+			    i2c_smbus_read_byte_data(client,
+						     ADM1029_REG_TEMP[nr]);
+		}
+		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
+			data->fan[nr] =
+			    i2c_smbus_read_byte_data(client,
+						     ADM1029_REG_FAN[nr]);
+		}
+		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
+			data->fan_div[nr] =
+			    i2c_smbus_read_byte_data(client,
+						     ADM1029_REG_FAN_DIV[nr]);
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+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 adm1029_data *data = adm1029_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm1029_data *data = adm1029_update_device(dev);
+	u16 val;
+	if (data->fan[attr->index] == 0
+	    || (data->fan_div[attr->index] & 0xC0) == 0
+	    || data->fan[attr->index] == 255) {
+		return sprintf(buf, "0\n");
+	}
+
+	val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
+	    / data->fan[attr->index];
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm1029_data *data = adm1029_update_device(dev);
+	if ((data->fan_div[attr->index] & 0xC0) == 0)
+		return sprintf(buf, "0\n");
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+	    struct device_attribute *devattr, const char *buf, size_t count)
+{
+	struct adm1029_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	u8 reg;
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+
+	/*Read actual config */
+	reg = i2c_smbus_read_byte_data(client,
+				       ADM1029_REG_FAN_DIV[attr->index]);
+
+	switch (val) {
+	case 1:
+		val = 1;
+		break;
+	case 2:
+		val = 2;
+		break;
+	case 4:
+		val = 3;
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		dev_err(&client->dev,
+			"fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",
+			val);
+		return -EINVAL;
+	}
+	/* Update the value */
+	reg = (reg & 0x3F) | (val << 6);
+
+	/* Update the cache */
+	data->fan_div[attr->index] = reg;
+
+	/* Write value */
+	i2c_smbus_write_byte_data(client,
+				  ADM1029_REG_FAN_DIV[attr->index], reg);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Access rights on sysfs. S_IRUGO: Is Readable by User, Group and Others
+ *			   S_IWUSR: Is Writable by User.
+ */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+			  show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+			  show_fan_div, set_fan_div, 1);
+
+static struct attribute *adm1029_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(adm1029);
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1029_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/*
+	 * ADM1029 doesn't have CHIP ID, check just MAN ID
+	 * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
+	 * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
+	 * documented
+	 */
+
+	man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
+	chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
+	temp_devices_installed = i2c_smbus_read_byte_data(client,
+					ADM1029_REG_TEMP_DEVICES_INSTALLED);
+	nb_fan_support = i2c_smbus_read_byte_data(client,
+						ADM1029_REG_NB_FAN_SUPPORT);
+	/* 0x41 is Analog Devices */
+	if (man_id != 0x41 || (temp_devices_installed & 0xf9) != 0x01
+	    || nb_fan_support != 0x03)
+		return -ENODEV;
+
+	if ((chip_id & 0xF0) != 0x00) {
+		/*
+		 * There are no "official" CHIP ID, so actually
+		 * we use Major/Minor revision for that
+		 */
+		pr_info("Unknown major revision %x, please let us know\n",
+			chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "adm1029", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int adm1029_init_client(struct i2c_client *client)
+{
+	u8 config;
+
+	config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+	if ((config & 0x10) == 0) {
+		i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
+					  config | 0x10);
+	}
+	/* recheck config */
+	config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+	if ((config & 0x10) == 0) {
+		dev_err(&client->dev, "Initialization failed!\n");
+		return 0;
+	}
+	return 1;
+}
+
+static int adm1029_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct adm1029_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct adm1029_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the ADM1029 chip
+	 * Check config register
+	 */
+	if (adm1029_init_client(client) == 0)
+		return -ENODEV;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   adm1029_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm1029_id[] = {
+	{ "adm1029", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1029_id);
+
+static struct i2c_driver adm1029_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name = "adm1029",
+	},
+	.probe		= adm1029_probe,
+	.id_table	= adm1029_id,
+	.detect		= adm1029_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm1029_driver);
+
+MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
+MODULE_DESCRIPTION("adm1029 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
new file mode 100644
index 0000000..a581898
--- /dev/null
+++ b/drivers/hwmon/adm1031.c
@@ -0,0 +1,1102 @@
+/*
+ * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Based on lm75.c and lm85.c
+ * Supports adm1030 / adm1031
+ * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
+ * Reworked by Jean Delvare <jdelvare@suse.de>
+ *
+ * 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>
+
+/* Following macros takes channel parameter starting from 0 to 2 */
+#define ADM1031_REG_FAN_SPEED(nr)	(0x08 + (nr))
+#define ADM1031_REG_FAN_DIV(nr)		(0x20 + (nr))
+#define ADM1031_REG_PWM			(0x22)
+#define ADM1031_REG_FAN_MIN(nr)		(0x10 + (nr))
+#define ADM1031_REG_FAN_FILTER		(0x23)
+
+#define ADM1031_REG_TEMP_OFFSET(nr)	(0x0d + (nr))
+#define ADM1031_REG_TEMP_MAX(nr)	(0x14 + 4 * (nr))
+#define ADM1031_REG_TEMP_MIN(nr)	(0x15 + 4 * (nr))
+#define ADM1031_REG_TEMP_CRIT(nr)	(0x16 + 4 * (nr))
+
+#define ADM1031_REG_TEMP(nr)		(0x0a + (nr))
+#define ADM1031_REG_AUTO_TEMP(nr)	(0x24 + (nr))
+
+#define ADM1031_REG_STATUS(nr)		(0x2 + (nr))
+
+#define ADM1031_REG_CONF1		0x00
+#define ADM1031_REG_CONF2		0x01
+#define ADM1031_REG_EXT_TEMP		0x06
+
+#define ADM1031_CONF1_MONITOR_ENABLE	0x01	/* Monitoring enable */
+#define ADM1031_CONF1_PWM_INVERT	0x08	/* PWM Invert */
+#define ADM1031_CONF1_AUTO_MODE		0x80	/* Auto FAN */
+
+#define ADM1031_CONF2_PWM1_ENABLE	0x01
+#define ADM1031_CONF2_PWM2_ENABLE	0x02
+#define ADM1031_CONF2_TACH1_ENABLE	0x04
+#define ADM1031_CONF2_TACH2_ENABLE	0x08
+#define ADM1031_CONF2_TEMP_ENABLE(chan)	(0x10 << (chan))
+
+#define ADM1031_UPDATE_RATE_MASK	0x1c
+#define ADM1031_UPDATE_RATE_SHIFT	2
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips { adm1030, adm1031 };
+
+typedef u8 auto_chan_table_t[8][2];
+
+/* Each client has this additional data */
+struct adm1031_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	int chip_type;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	unsigned int update_interval;	/* In milliseconds */
+	/*
+	 * The chan_select_table contains the possible configurations for
+	 * auto fan control.
+	 */
+	const auto_chan_table_t *chan_select_table;
+	u16 alarm;
+	u8 conf1;
+	u8 conf2;
+	u8 fan[2];
+	u8 fan_div[2];
+	u8 fan_min[2];
+	u8 pwm[2];
+	u8 old_pwm[2];
+	s8 temp[3];
+	u8 ext_temp[3];
+	u8 auto_temp[3];
+	u8 auto_temp_min[3];
+	u8 auto_temp_off[3];
+	u8 auto_temp_max[3];
+	s8 temp_offset[3];
+	s8 temp_min[3];
+	s8 temp_max[3];
+	s8 temp_crit[3];
+};
+
+static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int
+adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct adm1031_data *adm1031_update_device(struct device *dev)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long next_update;
+	int chan;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated
+	  + msecs_to_jiffies(data->update_interval);
+	if (time_after(jiffies, next_update) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting adm1031 update\n");
+		for (chan = 0;
+		     chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
+			u8 oldh, newh;
+
+			oldh =
+			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
+			data->ext_temp[chan] =
+			    adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
+			newh =
+			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
+			if (newh != oldh) {
+				data->ext_temp[chan] =
+				    adm1031_read_value(client,
+						       ADM1031_REG_EXT_TEMP);
+#ifdef DEBUG
+				oldh =
+				    adm1031_read_value(client,
+						       ADM1031_REG_TEMP(chan));
+
+				/* oldh is actually newer */
+				if (newh != oldh)
+					dev_warn(&client->dev,
+					  "Remote temperature may be wrong.\n");
+#endif
+			}
+			data->temp[chan] = newh;
+
+			data->temp_offset[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_TEMP_OFFSET(chan));
+			data->temp_min[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_TEMP_MIN(chan));
+			data->temp_max[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_TEMP_MAX(chan));
+			data->temp_crit[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_TEMP_CRIT(chan));
+			data->auto_temp[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_AUTO_TEMP(chan));
+
+		}
+
+		data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
+		data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
+
+		data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
+		    | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
+		if (data->chip_type == adm1030)
+			data->alarm &= 0xc0ff;
+
+		for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
+		     chan++) {
+			data->fan_div[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_FAN_DIV(chan));
+			data->fan_min[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_FAN_MIN(chan));
+			data->fan[chan] =
+			    adm1031_read_value(client,
+					       ADM1031_REG_FAN_SPEED(chan));
+			data->pwm[chan] =
+			  (adm1031_read_value(client,
+					ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+#define TEMP_TO_REG(val)		(((val) < 0 ? ((val - 500) / 1000) : \
+					((val + 500) / 1000)))
+
+#define TEMP_FROM_REG(val)		((val) * 1000)
+
+#define TEMP_FROM_REG_EXT(val, ext)	(TEMP_FROM_REG(val) + (ext) * 125)
+
+#define TEMP_OFFSET_TO_REG(val)		(TEMP_TO_REG(val) & 0x8f)
+#define TEMP_OFFSET_FROM_REG(val)	TEMP_FROM_REG((val) < 0 ? \
+						      (val) | 0x70 : (val))
+
+#define FAN_FROM_REG(reg, div)		((reg) ? \
+					 (11250 * 60) / ((reg) * (div)) : 0)
+
+static int FAN_TO_REG(int reg, int div)
+{
+	int tmp;
+	tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
+	return tmp > 255 ? 255 : tmp;
+}
+
+#define FAN_DIV_FROM_REG(reg)		(1<<(((reg)&0xc0)>>6))
+
+#define PWM_TO_REG(val)			(clamp_val((val), 0, 255) >> 4)
+#define PWM_FROM_REG(val)		((val) << 4)
+
+#define FAN_CHAN_FROM_REG(reg)		(((reg) >> 5) & 7)
+#define FAN_CHAN_TO_REG(val, reg)	\
+	(((reg) & 0x1F) | (((val) << 5) & 0xe0))
+
+#define AUTO_TEMP_MIN_TO_REG(val, reg)	\
+	((((val) / 500) & 0xf8) | ((reg) & 0x7))
+#define AUTO_TEMP_RANGE_FROM_REG(reg)	(5000 * (1 << ((reg) & 0x7)))
+#define AUTO_TEMP_MIN_FROM_REG(reg)	(1000 * ((((reg) >> 3) & 0x1f) << 2))
+
+#define AUTO_TEMP_MIN_FROM_REG_DEG(reg)	((((reg) >> 3) & 0x1f) << 2)
+
+#define AUTO_TEMP_OFF_FROM_REG(reg)		\
+	(AUTO_TEMP_MIN_FROM_REG(reg) - 5000)
+
+#define AUTO_TEMP_MAX_FROM_REG(reg)		\
+	(AUTO_TEMP_RANGE_FROM_REG(reg) +	\
+	AUTO_TEMP_MIN_FROM_REG(reg))
+
+static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
+{
+	int ret;
+	int range = val - AUTO_TEMP_MIN_FROM_REG(reg);
+
+	range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm);
+	ret = ((reg & 0xf8) |
+	       (range < 10000 ? 0 :
+		range < 20000 ? 1 :
+		range < 40000 ? 2 : range < 80000 ? 3 : 4));
+	return ret;
+}
+
+/* FAN auto control */
+#define GET_FAN_AUTO_BITFIELD(data, idx)	\
+	(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
+
+/*
+ * The tables below contains the possible values for the auto fan
+ * control bitfields. the index in the table is the register value.
+ * MSb is the auto fan control enable bit, so the four first entries
+ * in the table disables auto fan control when both bitfields are zero.
+ */
+static const auto_chan_table_t auto_channel_select_table_adm1031 = {
+	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
+	{ 2 /* 0b010 */ , 4 /* 0b100 */ },
+	{ 2 /* 0b010 */ , 2 /* 0b010 */ },
+	{ 4 /* 0b100 */ , 4 /* 0b100 */ },
+	{ 7 /* 0b111 */ , 7 /* 0b111 */ },
+};
+
+static const auto_chan_table_t auto_channel_select_table_adm1030 = {
+	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
+	{ 2 /* 0b10 */		, 0 },
+	{ 0xff /* invalid */	, 0 },
+	{ 0xff /* invalid */	, 0 },
+	{ 3 /* 0b11 */		, 0 },
+};
+
+/*
+ * That function checks if a bitfield is valid and returns the other bitfield
+ * nearest match if no exact match where found.
+ */
+static int
+get_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg)
+{
+	int i;
+	int first_match = -1, exact_match = -1;
+	u8 other_reg_val =
+	    (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1];
+
+	if (val == 0)
+		return 0;
+
+	for (i = 0; i < 8; i++) {
+		if ((val == (*data->chan_select_table)[i][chan]) &&
+		    ((*data->chan_select_table)[i][chan ? 0 : 1] ==
+		     other_reg_val)) {
+			/* We found an exact match */
+			exact_match = i;
+			break;
+		} else if (val == (*data->chan_select_table)[i][chan] &&
+			   first_match == -1) {
+			/*
+			 * Save the first match in case of an exact match has
+			 * not been found
+			 */
+			first_match = i;
+		}
+	}
+
+	if (exact_match >= 0)
+		return exact_match;
+	else if (first_match >= 0)
+		return first_match;
+
+	return -EINVAL;
+}
+
+static ssize_t show_fan_auto_channel(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr));
+}
+
+static ssize_t
+set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	u8 reg;
+	int ret;
+	u8 old_fan_mode;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	old_fan_mode = data->conf1;
+
+	mutex_lock(&data->update_lock);
+
+	ret = get_fan_auto_nearest(data, nr, val, data->conf1);
+	if (ret < 0) {
+		mutex_unlock(&data->update_lock);
+		return ret;
+	}
+	reg = ret;
+	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
+	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
+	    (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
+		if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
+			/*
+			 * Switch to Auto Fan Mode
+			 * Save PWM registers
+			 * Set PWM registers to 33% Both
+			 */
+			data->old_pwm[0] = data->pwm[0];
+			data->old_pwm[1] = data->pwm[1];
+			adm1031_write_value(client, ADM1031_REG_PWM, 0x55);
+		} else {
+			/* Switch to Manual Mode */
+			data->pwm[0] = data->old_pwm[0];
+			data->pwm[1] = data->old_pwm[1];
+			/* Restore PWM registers */
+			adm1031_write_value(client, ADM1031_REG_PWM,
+					    data->pwm[0] | (data->pwm[1] << 4));
+		}
+	}
+	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
+	adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(auto_fan1_channel, S_IRUGO | S_IWUSR,
+		show_fan_auto_channel, set_fan_auto_channel, 0);
+static SENSOR_DEVICE_ATTR(auto_fan2_channel, S_IRUGO | S_IWUSR,
+		show_fan_auto_channel, set_fan_auto_channel, 1);
+
+/* Auto Temps */
+static ssize_t show_auto_temp_off(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr]));
+}
+static ssize_t show_auto_temp_min(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr]));
+}
+static ssize_t
+set_auto_temp_min(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, 0, 127000);
+	mutex_lock(&data->update_lock);
+	data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
+	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
+			    data->auto_temp[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t show_auto_temp_max(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr]));
+}
+static ssize_t
+set_auto_temp_max(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, 0, 127000);
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
+						  data->pwm[nr]);
+	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
+			    data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define auto_temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO,		\
+		show_auto_temp_off, NULL, offset - 1);			\
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_auto_temp_min, set_auto_temp_min, offset - 1);	\
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_auto_temp_max, set_auto_temp_max, offset - 1)
+
+auto_temp_reg(1);
+auto_temp_reg(2);
+auto_temp_reg(3);
+
+/* pwm */
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret, reg;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
+	    (((val>>4) & 0xf) != 5)) {
+		/* In automatic mode, the only PWM accepted is 33% */
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+	data->pwm[nr] = PWM_TO_REG(val);
+	reg = adm1031_read_value(client, ADM1031_REG_PWM);
+	adm1031_write_value(client, ADM1031_REG_PWM,
+			    nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf)
+			    : (data->pwm[nr] & 0xf) | (reg & 0xf0));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(auto_fan1_min_pwm, S_IRUGO | S_IWUSR,
+		show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(auto_fan2_min_pwm, S_IRUGO | S_IWUSR,
+		show_pwm, set_pwm, 1);
+
+/* Fans */
+
+/*
+ * That function checks the cases where the fan reading is not
+ * relevant.  It is used to provide 0 as fan reading when the fan is
+ * not supposed to run
+ */
+static int trust_fan_readings(struct adm1031_data *data, int chan)
+{
+	int res = 0;
+
+	if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
+		switch (data->conf1 & 0x60) {
+		case 0x00:
+			/*
+			 * remote temp1 controls fan1,
+			 * remote temp2 controls fan2
+			 */
+			res = data->temp[chan+1] >=
+			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
+			break;
+		case 0x20:	/* remote temp1 controls both fans */
+			res =
+			    data->temp[1] >=
+			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]);
+			break;
+		case 0x40:	/* remote temp2 controls both fans */
+			res =
+			    data->temp[2] >=
+			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]);
+			break;
+		case 0x60:	/* max controls both fans */
+			res =
+			    data->temp[0] >=
+			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0])
+			    || data->temp[1] >=
+			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1])
+			    || (data->chip_type == adm1031
+				&& data->temp[2] >=
+				AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]));
+			break;
+		}
+	} else {
+		res = data->pwm[chan] > 0;
+	}
+	return res;
+}
+
+
+static ssize_t show_fan(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	int value;
+
+	value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr],
+				 FAN_DIV_FROM_REG(data->fan_div[nr])) : 0;
+	return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_fan_div(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));
+}
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       FAN_FROM_REG(data->fan_min[nr],
+				    FAN_DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	if (val) {
+		data->fan_min[nr] =
+			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
+	} else {
+		data->fan_min[nr] = 0xff;
+	}
+	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	u8 tmp;
+	int old_div;
+	int new_min;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	tmp = val == 8 ? 0xc0 :
+	      val == 4 ? 0x80 :
+	      val == 2 ? 0x40 :
+	      val == 1 ? 0x00 :
+	      0xff;
+	if (tmp == 0xff)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	/* Get fresh readings */
+	data->fan_div[nr] = adm1031_read_value(client,
+					       ADM1031_REG_FAN_DIV(nr));
+	data->fan_min[nr] = adm1031_read_value(client,
+					       ADM1031_REG_FAN_MIN(nr));
+
+	/* Write the new clock divider and fan min */
+	old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
+	data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]);
+	new_min = data->fan_min[nr] * old_div / val;
+	data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;
+
+	adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
+			    data->fan_div[nr]);
+	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
+			    data->fan_min[nr]);
+
+	/* Invalidate the cache: fan speed is no longer valid */
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define fan_offset(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1)
+
+fan_offset(1);
+fan_offset(2);
+
+
+/* Temps */
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	int ext;
+	ext = nr == 0 ?
+	    ((data->ext_temp[nr] >> 6) & 0x3) * 2 :
+	    (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));
+	return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));
+}
+static ssize_t show_temp_offset(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       TEMP_OFFSET_FROM_REG(data->temp_offset[nr]));
+}
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+static ssize_t show_temp_crit(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
+}
+static ssize_t set_temp_offset(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, -15000, 15000);
+	mutex_lock(&data->update_lock);
+	data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
+	adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
+			    data->temp_offset[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, -55000, 127000);
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = TEMP_TO_REG(val);
+	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
+			    data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, -55000, 127000);
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = TEMP_TO_REG(val);
+	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
+			    data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	val = clamp_val(val, -55000, 127000);
+	mutex_lock(&data->update_lock);
+	data->temp_crit[nr] = TEMP_TO_REG(val);
+	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
+			    data->temp_crit[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+		show_temp, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR,	\
+		show_temp_offset, set_temp_offset, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_temp_min, set_temp_min, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_max, set_temp_max, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR,	\
+		show_temp_crit, set_temp_crit, offset - 1)
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarm);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct adm1031_data *data = adm1031_update_device(dev);
+	return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+/* Update Interval */
+static const unsigned int update_intervals[] = {
+	16000, 8000, 4000, 2000, 1000, 500, 250, 125,
+};
+
+static ssize_t show_update_interval(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct adm1031_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int i, err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/*
+	 * Find the nearest update interval from the table.
+	 * Use it to determine the matching update rate.
+	 */
+	for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) {
+		if (val >= update_intervals[i])
+			break;
+	}
+	/* if not found, we point to the last entry (lowest update interval) */
+
+	/* set the new update rate while preserving other settings */
+	reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+	reg &= ~ADM1031_UPDATE_RATE_MASK;
+	reg |= i << ADM1031_UPDATE_RATE_SHIFT;
+	adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
+
+	mutex_lock(&data->update_lock);
+	data->update_interval = update_intervals[i];
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+		   set_update_interval);
+
+static struct attribute *adm1031_attributes[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_auto_fan1_channel.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+	&sensor_dev_attr_auto_temp1_off.dev_attr.attr,
+	&sensor_dev_attr_auto_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_auto_temp1_max.dev_attr.attr,
+
+	&sensor_dev_attr_auto_temp2_off.dev_attr.attr,
+	&sensor_dev_attr_auto_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_auto_temp2_max.dev_attr.attr,
+
+	&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
+
+	&dev_attr_update_interval.attr,
+	&dev_attr_alarms.attr,
+
+	NULL
+};
+
+static const struct attribute_group adm1031_group = {
+	.attrs = adm1031_attributes,
+};
+
+static struct attribute *adm1031_attributes_opt[] = {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_auto_fan2_channel.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_auto_temp3_off.dev_attr.attr,
+	&sensor_dev_attr_auto_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_auto_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adm1031_group_opt = {
+	.attrs = adm1031_attributes_opt,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1031_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	const char *name;
+	int id, co;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	id = i2c_smbus_read_byte_data(client, 0x3d);
+	co = i2c_smbus_read_byte_data(client, 0x3e);
+
+	if (!((id == 0x31 || id == 0x30) && co == 0x41))
+		return -ENODEV;
+	name = (id == 0x30) ? "adm1030" : "adm1031";
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adm1031_init_client(struct i2c_client *client)
+{
+	unsigned int read_val;
+	unsigned int mask;
+	int i;
+	struct adm1031_data *data = i2c_get_clientdata(client);
+
+	mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
+	if (data->chip_type == adm1031) {
+		mask |= (ADM1031_CONF2_PWM2_ENABLE |
+			ADM1031_CONF2_TACH2_ENABLE);
+	}
+	/* Initialize the ADM1031 chip (enables fan speed reading ) */
+	read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
+	if ((read_val | mask) != read_val)
+		adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
+
+	read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
+	if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
+		adm1031_write_value(client, ADM1031_REG_CONF1,
+				    read_val | ADM1031_CONF1_MONITOR_ENABLE);
+	}
+
+	/* Read the chip's update rate */
+	mask = ADM1031_UPDATE_RATE_MASK;
+	read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+	i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
+	/* Save it as update interval */
+	data->update_interval = update_intervals[i];
+}
+
+static int adm1031_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct adm1031_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	data->chip_type = id->driver_data;
+	mutex_init(&data->update_lock);
+
+	if (data->chip_type == adm1030)
+		data->chan_select_table = &auto_channel_select_table_adm1030;
+	else
+		data->chan_select_table = &auto_channel_select_table_adm1031;
+
+	/* Initialize the ADM1031 chip */
+	adm1031_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &adm1031_group;
+	if (data->chip_type == adm1031)
+		data->groups[1] = &adm1031_group_opt;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm1031_id[] = {
+	{ "adm1030", adm1030 },
+	{ "adm1031", adm1031 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1031_id);
+
+static struct i2c_driver adm1031_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name = "adm1031",
+	},
+	.probe		= adm1031_probe,
+	.id_table	= adm1031_id,
+	.detect		= adm1031_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm1031_driver);
+
+MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
+MODULE_DESCRIPTION("ADM1031/ADM1030 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
new file mode 100644
index 0000000..98114ce
--- /dev/null
+++ b/drivers/hwmon/adm9240.c
@@ -0,0 +1,770 @@
+/*
+ * adm9240.c	Part of lm_sensors, Linux kernel modules for hardware
+ *		monitoring
+ *
+ * Copyright (C) 1999	Frodo Looijaard <frodol@dds.nl>
+ *			Philip Edelbrock <phil@netroedge.com>
+ * Copyright (C) 2003	Michiel Rook <michiel@grendelproject.nl>
+ * Copyright (C) 2005	Grant Coady <gcoady.lk@gmail.com> with valuable
+ *				guidance from Jean Delvare
+ *
+ * Driver supports	Analog Devices		ADM9240
+ *			Dallas Semiconductor	DS1780
+ *			National Semiconductor	LM81
+ *
+ * ADM9240 is the reference, DS1780 and LM81 are register compatibles
+ *
+ * Voltage	Six inputs are scaled by chip, VID also reported
+ * Temperature	Chip temperature to 0.5'C, maximum and max_hysteris
+ * Fans		2 fans, low speed alarm, automatic fan clock divider
+ * Alarms	16-bit map of active alarms
+ * Analog Out	0..1250 mV output
+ *
+ * Chassis Intrusion: clear CI latch with 'echo 0 > intrusion0_alarm'
+ *
+ * Test hardware: Intel SE440BX-2 desktop motherboard --Grant
+ *
+ * LM81 extended temp reading not implemented
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+					I2C_CLIENT_END };
+
+enum chips { adm9240, ds1780, lm81 };
+
+/* ADM9240 registers */
+#define ADM9240_REG_MAN_ID		0x3e
+#define ADM9240_REG_DIE_REV		0x3f
+#define ADM9240_REG_CONFIG		0x40
+
+#define ADM9240_REG_IN(nr)		(0x20 + (nr))   /* 0..5 */
+#define ADM9240_REG_IN_MAX(nr)		(0x2b + (nr) * 2)
+#define ADM9240_REG_IN_MIN(nr)		(0x2c + (nr) * 2)
+#define ADM9240_REG_FAN(nr)		(0x28 + (nr))   /* 0..1 */
+#define ADM9240_REG_FAN_MIN(nr)		(0x3b + (nr))
+#define ADM9240_REG_INT(nr)		(0x41 + (nr))
+#define ADM9240_REG_INT_MASK(nr)	(0x43 + (nr))
+#define ADM9240_REG_TEMP		0x27
+#define ADM9240_REG_TEMP_MAX(nr)	(0x39 + (nr)) /* 0, 1 = high, hyst */
+#define ADM9240_REG_ANALOG_OUT		0x19
+#define ADM9240_REG_CHASSIS_CLEAR	0x46
+#define ADM9240_REG_VID_FAN_DIV		0x47
+#define ADM9240_REG_I2C_ADDR		0x48
+#define ADM9240_REG_VID4		0x49
+#define ADM9240_REG_TEMP_CONF		0x4b
+
+/* generalised scaling with integer rounding */
+static inline int SCALE(long val, int mul, int div)
+{
+	if (val < 0)
+		return (val * mul - div / 2) / div;
+	else
+		return (val * mul + div / 2) / div;
+}
+
+/* adm9240 internally scales voltage measurements */
+static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
+
+static inline unsigned int IN_FROM_REG(u8 reg, int n)
+{
+	return SCALE(reg, nom_mv[n], 192);
+}
+
+static inline u8 IN_TO_REG(unsigned long val, int n)
+{
+	return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
+}
+
+/* temperature range: -40..125, 127 disables temperature alarm */
+static inline s8 TEMP_TO_REG(long val)
+{
+	return clamp_val(SCALE(val, 1, 1000), -40, 127);
+}
+
+/* two fans, each with low fan speed limit */
+static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
+{
+	if (!reg) /* error */
+		return -1;
+
+	if (reg == 255)
+		return 0;
+
+	return SCALE(1350000, 1, reg * div);
+}
+
+/* analog out 0..1250mV */
+static inline u8 AOUT_TO_REG(unsigned long val)
+{
+	return clamp_val(SCALE(val, 255, 1250), 0, 255);
+}
+
+static inline unsigned int AOUT_FROM_REG(u8 reg)
+{
+	return SCALE(reg, 1250, 255);
+}
+
+/* per client data */
+struct adm9240_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;
+	unsigned long last_updated_measure;
+	unsigned long last_updated_config;
+
+	u8 in[6];		/* ro	in0_input */
+	u8 in_max[6];		/* rw	in0_max */
+	u8 in_min[6];		/* rw	in0_min */
+	u8 fan[2];		/* ro	fan1_input */
+	u8 fan_min[2];		/* rw	fan1_min */
+	u8 fan_div[2];		/* rw	fan1_div, read-only accessor */
+	s16 temp;		/* ro	temp1_input, 9-bit sign-extended */
+	s8 temp_max[2];		/* rw	0 -> temp_max, 1 -> temp_max_hyst */
+	u16 alarms;		/* ro	alarms */
+	u8 aout;		/* rw	aout_output */
+	u8 vid;			/* ro	vid */
+	u8 vrm;			/* --	vrm set on startup, no accessor */
+};
+
+/* write new fan div, callers must hold data->update_lock */
+static void adm9240_write_fan_div(struct i2c_client *client, int nr,
+		u8 fan_div)
+{
+	u8 reg, old, shift = (nr + 2) * 2;
+
+	reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
+	old = (reg >> shift) & 3;
+	reg &= ~(3 << shift);
+	reg |= (fan_div << shift);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
+	dev_dbg(&client->dev,
+		"fan%d clock divider changed from %u to %u\n",
+		nr + 1, 1 << old, 1 << fan_div);
+}
+
+static struct adm9240_data *adm9240_update_device(struct device *dev)
+{
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	/* minimum measurement cycle: 1.75 seconds */
+	if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
+			|| !data->valid) {
+
+		for (i = 0; i < 6; i++) { /* read voltages */
+			data->in[i] = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_IN(i));
+		}
+		data->alarms = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_INT(0)) |
+					i2c_smbus_read_byte_data(client,
+					ADM9240_REG_INT(1)) << 8;
+
+		/*
+		 * read temperature: assume temperature changes less than
+		 * 0.5'C per two measurement cycles thus ignore possible
+		 * but unlikely aliasing error on lsb reading. --Grant
+		 */
+		data->temp = ((i2c_smbus_read_byte_data(client,
+					ADM9240_REG_TEMP) << 8) |
+					i2c_smbus_read_byte_data(client,
+					ADM9240_REG_TEMP_CONF)) / 128;
+
+		for (i = 0; i < 2; i++) { /* read fans */
+			data->fan[i] = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_FAN(i));
+
+			/* adjust fan clock divider on overflow */
+			if (data->valid && data->fan[i] == 255 &&
+					data->fan_div[i] < 3) {
+
+				adm9240_write_fan_div(client, i,
+						++data->fan_div[i]);
+
+				/* adjust fan_min if active, but not to 0 */
+				if (data->fan_min[i] < 255 &&
+						data->fan_min[i] >= 2)
+					data->fan_min[i] /= 2;
+			}
+		}
+		data->last_updated_measure = jiffies;
+	}
+
+	/* minimum config reading cycle: 300 seconds */
+	if (time_after(jiffies, data->last_updated_config + (HZ * 300))
+			|| !data->valid) {
+
+		for (i = 0; i < 6; i++) {
+			data->in_min[i] = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_IN_MIN(i));
+			data->in_max[i] = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 2; i++) {
+			data->fan_min[i] = i2c_smbus_read_byte_data(client,
+					ADM9240_REG_FAN_MIN(i));
+		}
+		data->temp_max[0] = i2c_smbus_read_byte_data(client,
+				ADM9240_REG_TEMP_MAX(0));
+		data->temp_max[1] = i2c_smbus_read_byte_data(client,
+				ADM9240_REG_TEMP_MAX(1));
+
+		/* read fan divs and 5-bit VID */
+		i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
+		data->fan_div[0] = (i >> 4) & 3;
+		data->fan_div[1] = (i >> 6) & 3;
+		data->vid = i & 0x0f;
+		data->vid |= (i2c_smbus_read_byte_data(client,
+					ADM9240_REG_VID4) & 1) << 4;
+		/* read analog out */
+		data->aout = i2c_smbus_read_byte_data(client,
+				ADM9240_REG_ANALOG_OUT);
+
+		data->last_updated_config = jiffies;
+		data->valid = 1;
+	}
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*** sysfs accessors ***/
+
+/* temperature */
+static ssize_t show_temp(struct device *dev, struct device_attribute *dummy,
+		char *buf)
+{
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */
+}
+
+static ssize_t show_max(struct device *dev, struct device_attribute *devattr,
+		char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000);
+}
+
+static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[attr->index] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index),
+			data->temp_max[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+		show_max, set_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+		show_max, set_max, 1);
+
+/* voltage */
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+		char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index],
+				attr->index));
+}
+
+static ssize_t show_in_min(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index],
+				attr->index));
+}
+
+static ssize_t show_in_max(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index],
+				attr->index));
+}
+
+static ssize_t set_in_min(struct device *dev,
+		struct device_attribute *devattr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[attr->index] = IN_TO_REG(val, attr->index);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index),
+			data->in_min[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev,
+		struct device_attribute *devattr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[attr->index] = IN_TO_REG(val, attr->index);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index),
+			data->in_max[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define vin(nr)							\
+static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO,		\
+		show_in, NULL, nr);				\
+static SENSOR_DEVICE_ATTR(in##nr##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, nr);			\
+static SENSOR_DEVICE_ATTR(in##nr##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, nr);
+
+vin(0);
+vin(1);
+vin(2);
+vin(3);
+vin(4);
+vin(5);
+
+/* fans */
+static ssize_t show_fan(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
+				1 << data->fan_div[attr->index]));
+}
+
+static ssize_t show_fan_min(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index],
+				1 << data->fan_div[attr->index]));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]);
+}
+
+/*
+ * set fan speed low limit:
+ *
+ * - value is zero: disable fan speed low limit alarm
+ *
+ * - value is below fan speed measurement range: enable fan speed low
+ *   limit alarm to be asserted while fan speed too slow to measure
+ *
+ * - otherwise: select fan clock divider to suit fan speed low limit,
+ *   measurement code may adjust registers to ensure fan speed reading
+ */
+static ssize_t set_fan_min(struct device *dev,
+		struct device_attribute *devattr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	u8 new_div;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	if (!val) {
+		data->fan_min[nr] = 255;
+		new_div = data->fan_div[nr];
+
+		dev_dbg(&client->dev, "fan%u low limit set disabled\n",
+				nr + 1);
+
+	} else if (val < 1350000 / (8 * 254)) {
+		new_div = 3;
+		data->fan_min[nr] = 254;
+
+		dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
+				nr + 1, FAN_FROM_REG(254, 1 << new_div));
+
+	} else {
+		unsigned int new_min = 1350000 / val;
+
+		new_div = 0;
+		while (new_min > 192 && new_div < 3) {
+			new_div++;
+			new_min /= 2;
+		}
+		if (!new_min) /* keep > 0 */
+			new_min++;
+
+		data->fan_min[nr] = new_min;
+
+		dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
+				nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
+	}
+
+	if (new_div != data->fan_div[nr]) {
+		data->fan_div[nr] = new_div;
+		adm9240_write_fan_div(client, nr, new_div);
+	}
+	i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr),
+			data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define fan(nr)							\
+static SENSOR_DEVICE_ATTR(fan##nr##_input, S_IRUGO,		\
+		show_fan, NULL, nr - 1);			\
+static SENSOR_DEVICE_ATTR(fan##nr##_div, S_IRUGO,		\
+		show_fan_div, NULL, nr - 1);			\
+static SENSOR_DEVICE_ATTR(fan##nr##_min, S_IRUGO | S_IWUSR,	\
+		show_fan_min, set_fan_min, nr - 1);
+
+fan(1);
+fan(2);
+
+/* alarms */
+static ssize_t show_alarms(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
+/* vid */
+static ssize_t show_vid(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* analog output */
+static ssize_t show_aout(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct adm9240_data *data = adm9240_update_device(dev);
+	return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+}
+
+static ssize_t set_aout(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->aout = AOUT_TO_REG(val);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+
+static ssize_t chassis_clear(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct adm9240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
+	data->valid = 0;		/* Force cache refresh */
+	mutex_unlock(&data->update_lock);
+	dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
+
+	return count;
+}
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, show_alarm,
+		chassis_clear, 12);
+
+static struct attribute *adm9240_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&dev_attr_temp1_input.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_aout_output.attr,
+	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
+	&dev_attr_cpu0_vid.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(adm9240);
+
+
+/*** sensor chip detect and driver install ***/
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm9240_detect(struct i2c_client *new_client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	const char *name = "";
+	int address = new_client->addr;
+	u8 man_id, die_rev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* verify chip: reg address should match i2c address */
+	if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR)
+			!= address) {
+		dev_err(&adapter->dev, "detect fail: address match, 0x%02x\n",
+			address);
+		return -ENODEV;
+	}
+
+	/* check known chip manufacturer */
+	man_id = i2c_smbus_read_byte_data(new_client, ADM9240_REG_MAN_ID);
+	if (man_id == 0x23) {
+		name = "adm9240";
+	} else if (man_id == 0xda) {
+		name = "ds1780";
+	} else if (man_id == 0x01) {
+		name = "lm81";
+	} else {
+		dev_err(&adapter->dev, "detect fail: unknown manuf, 0x%02x\n",
+			man_id);
+		return -ENODEV;
+	}
+
+	/* successful detect, print chip info */
+	die_rev = i2c_smbus_read_byte_data(new_client, ADM9240_REG_DIE_REV);
+	dev_info(&adapter->dev, "found %s revision %u\n",
+		 man_id == 0x23 ? "ADM9240" :
+		 man_id == 0xda ? "DS1780" : "LM81", die_rev);
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adm9240_init_client(struct i2c_client *client)
+{
+	struct adm9240_data *data = i2c_get_clientdata(client);
+	u8 conf = i2c_smbus_read_byte_data(client, ADM9240_REG_CONFIG);
+	u8 mode = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF) & 3;
+
+	data->vrm = vid_which_vrm(); /* need this to report vid as mV */
+
+	dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
+			data->vrm % 10);
+
+	if (conf & 1) { /* measurement cycle running: report state */
+
+		dev_info(&client->dev, "status: config 0x%02x mode %u\n",
+				conf, mode);
+
+	} else { /* cold start: open limits before starting chip */
+		int i;
+
+		for (i = 0; i < 6; i++) {
+			i2c_smbus_write_byte_data(client,
+					ADM9240_REG_IN_MIN(i), 0);
+			i2c_smbus_write_byte_data(client,
+					ADM9240_REG_IN_MAX(i), 255);
+		}
+		i2c_smbus_write_byte_data(client,
+				ADM9240_REG_FAN_MIN(0), 255);
+		i2c_smbus_write_byte_data(client,
+				ADM9240_REG_FAN_MIN(1), 255);
+		i2c_smbus_write_byte_data(client,
+				ADM9240_REG_TEMP_MAX(0), 127);
+		i2c_smbus_write_byte_data(client,
+				ADM9240_REG_TEMP_MAX(1), 127);
+
+		/* start measurement cycle */
+		i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
+
+		dev_info(&client->dev,
+			 "cold start: config was 0x%02x mode %u\n", conf, mode);
+	}
+}
+
+static int adm9240_probe(struct i2c_client *new_client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &new_client->dev;
+	struct device *hwmon_dev;
+	struct adm9240_data *data;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(new_client, data);
+	data->client = new_client;
+	mutex_init(&data->update_lock);
+
+	adm9240_init_client(new_client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   new_client->name,
+							   data,
+							   adm9240_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adm9240_id[] = {
+	{ "adm9240", adm9240 },
+	{ "ds1780", ds1780 },
+	{ "lm81", lm81 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm9240_id);
+
+static struct i2c_driver adm9240_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adm9240",
+	},
+	.probe		= adm9240_probe,
+	.id_table	= adm9240_id,
+	.detect		= adm9240_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adm9240_driver);
+
+MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
+		"Grant Coady <gcoady.lk@gmail.com> and others");
+MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
new file mode 100644
index 0000000..2b3105c
--- /dev/null
+++ b/drivers/hwmon/ads1015.c
@@ -0,0 +1,319 @@
+/*
+ * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
+ * (C) Copyright 2010
+ * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
+ *
+ * Based on the ads7828 driver by Steve Hardy.
+ *
+ * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+
+#include <linux/i2c/ads1015.h>
+
+/* ADS1015 registers */
+enum {
+	ADS1015_CONVERSION = 0,
+	ADS1015_CONFIG = 1,
+};
+
+/* PGA fullscale voltages in mV */
+static const unsigned int fullscale_table[8] = {
+	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
+
+/* Data rates in samples per second */
+static const unsigned int data_rate_table_1015[8] = {
+	128, 250, 490, 920, 1600, 2400, 3300, 3300
+};
+
+static const unsigned int data_rate_table_1115[8] = {
+	8, 16, 32, 64, 128, 250, 475, 860
+};
+
+#define ADS1015_DEFAULT_CHANNELS 0xff
+#define ADS1015_DEFAULT_PGA 2
+#define ADS1015_DEFAULT_DATA_RATE 4
+
+enum ads1015_chips {
+	ads1015,
+	ads1115,
+};
+
+struct ads1015_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock; /* mutex protect updates */
+	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+	enum ads1015_chips id;
+};
+
+static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
+{
+	u16 config;
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	unsigned int pga = data->channel_data[channel].pga;
+	unsigned int data_rate = data->channel_data[channel].data_rate;
+	unsigned int conversion_time_ms;
+	const unsigned int * const rate_table = data->id == ads1115 ?
+		data_rate_table_1115 : data_rate_table_1015;
+	int res;
+
+	mutex_lock(&data->update_lock);
+
+	/* get channel parameters */
+	res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
+	if (res < 0)
+		goto err_unlock;
+	config = res;
+	conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
+
+	/* setup and start single conversion */
+	config &= 0x001f;
+	config |= (1 << 15) | (1 << 8);
+	config |= (channel & 0x0007) << 12;
+	config |= (pga & 0x0007) << 9;
+	config |= (data_rate & 0x0007) << 5;
+
+	res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config);
+	if (res < 0)
+		goto err_unlock;
+
+	/* wait until conversion finished */
+	msleep(conversion_time_ms);
+	res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
+	if (res < 0)
+		goto err_unlock;
+	config = res;
+	if (!(config & (1 << 15))) {
+		/* conversion not finished in time */
+		res = -EIO;
+		goto err_unlock;
+	}
+
+	res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION);
+
+err_unlock:
+	mutex_unlock(&data->update_lock);
+	return res;
+}
+
+static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
+			     s16 reg)
+{
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	unsigned int pga = data->channel_data[channel].pga;
+	int fullscale = fullscale_table[pga];
+	const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
+
+	return DIV_ROUND_CLOSEST(reg * fullscale, mask);
+}
+
+/* sysfs callback function */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+	char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	int res;
+	int index = attr->index;
+
+	res = ads1015_read_adc(client, index);
+	if (res < 0)
+		return res;
+
+	return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res));
+}
+
+static const struct sensor_device_attribute ads1015_in[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+};
+
+/*
+ * Driver interface
+ */
+
+static int ads1015_remove(struct i2c_client *client)
+{
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	int k;
+
+	hwmon_device_unregister(data->hwmon_dev);
+	for (k = 0; k < ADS1015_CHANNELS; ++k)
+		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int ads1015_get_channels_config_of(struct i2c_client *client)
+{
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	struct device_node *node;
+
+	if (!client->dev.of_node
+	    || !of_get_next_child(client->dev.of_node, NULL))
+		return -EINVAL;
+
+	for_each_child_of_node(client->dev.of_node, node) {
+		u32 pval;
+		unsigned int channel;
+		unsigned int pga = ADS1015_DEFAULT_PGA;
+		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
+
+		if (of_property_read_u32(node, "reg", &pval)) {
+			dev_err(&client->dev, "invalid reg on %s\n",
+				node->full_name);
+			continue;
+		}
+
+		channel = pval;
+		if (channel >= ADS1015_CHANNELS) {
+			dev_err(&client->dev,
+				"invalid channel index %d on %s\n",
+				channel, node->full_name);
+			continue;
+		}
+
+		if (!of_property_read_u32(node, "ti,gain", &pval)) {
+			pga = pval;
+			if (pga > 6) {
+				dev_err(&client->dev, "invalid gain on %s\n",
+					node->full_name);
+				return -EINVAL;
+			}
+		}
+
+		if (!of_property_read_u32(node, "ti,datarate", &pval)) {
+			data_rate = pval;
+			if (data_rate > 7) {
+				dev_err(&client->dev,
+					"invalid data_rate on %s\n",
+					node->full_name);
+				return -EINVAL;
+			}
+		}
+
+		data->channel_data[channel].enabled = true;
+		data->channel_data[channel].pga = pga;
+		data->channel_data[channel].data_rate = data_rate;
+	}
+
+	return 0;
+}
+#endif
+
+static void ads1015_get_channels_config(struct i2c_client *client)
+{
+	unsigned int k;
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
+
+	/* prefer platform data */
+	if (pdata) {
+		memcpy(data->channel_data, pdata->channel_data,
+		       sizeof(data->channel_data));
+		return;
+	}
+
+#ifdef CONFIG_OF
+	if (!ads1015_get_channels_config_of(client))
+		return;
+#endif
+
+	/* fallback on default configuration */
+	for (k = 0; k < ADS1015_CHANNELS; ++k) {
+		data->channel_data[k].enabled = true;
+		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
+		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
+	}
+}
+
+static int ads1015_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct ads1015_data *data;
+	int err;
+	unsigned int k;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	data->id = id->driver_data;
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* build sysfs attribute group */
+	ads1015_get_channels_config(client);
+	for (k = 0; k < ADS1015_CHANNELS; ++k) {
+		if (!data->channel_data[k].enabled)
+			continue;
+		err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	for (k = 0; k < ADS1015_CHANNELS; ++k)
+		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
+	return err;
+}
+
+static const struct i2c_device_id ads1015_id[] = {
+	{ "ads1015",  ads1015},
+	{ "ads1115",  ads1115},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ads1015_id);
+
+static struct i2c_driver ads1015_driver = {
+	.driver = {
+		.name = "ads1015",
+	},
+	.probe = ads1015_probe,
+	.remove = ads1015_remove,
+	.id_table = ads1015_id,
+};
+
+module_i2c_driver(ads1015_driver);
+
+MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
+MODULE_DESCRIPTION("ADS1015 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
new file mode 100644
index 0000000..ee396ff
--- /dev/null
+++ b/drivers/hwmon/ads7828.c
@@ -0,0 +1,193 @@
+/*
+ * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
+ * (C) 2007 EADS Astrium
+ *
+ * This driver is based on the lm75 and other lm_sensors/hwmon drivers
+ *
+ * Written by Steve Hardy <shardy@redhat.com>
+ *
+ * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
+ * For further information, see the Documentation/hwmon/ads7828 file.
+ *
+ * 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/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_data/ads7828.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* The ADS7828 registers */
+#define ADS7828_CMD_SD_SE	0x80	/* Single ended inputs */
+#define ADS7828_CMD_PD1		0x04	/* Internal vref OFF && A/D ON */
+#define ADS7828_CMD_PD3		0x0C	/* Internal vref ON && A/D ON */
+#define ADS7828_INT_VREF_MV	2500	/* Internal vref is 2.5V, 2500mV */
+#define ADS7828_EXT_VREF_MV_MIN	50	/* External vref min value 0.05V */
+#define ADS7828_EXT_VREF_MV_MAX	5250	/* External vref max value 5.25V */
+
+/* List of supported devices */
+enum ads7828_chips { ads7828, ads7830 };
+
+/* Client specific data */
+struct ads7828_data {
+	struct regmap *regmap;
+	u8 cmd_byte;			/* Command byte without channel bits */
+	unsigned int lsb_resol;		/* Resolution of the ADC sample LSB */
+};
+
+/* Command byte C2,C1,C0 - see datasheet */
+static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
+{
+	return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
+}
+
+/* sysfs callback function */
+static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
+			       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ads7828_data *data = dev_get_drvdata(dev);
+	u8 cmd = ads7828_cmd_byte(data->cmd_byte, attr->index);
+	unsigned int regval;
+	int err;
+
+	err = regmap_read(data->regmap, cmd, &regval);
+	if (err < 0)
+		return err;
+
+	return sprintf(buf, "%d\n",
+		       DIV_ROUND_CLOSEST(regval * data->lsb_resol, 1000));
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
+
+static struct attribute *ads7828_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(ads7828);
+
+static const struct regmap_config ads2828_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+};
+
+static const struct regmap_config ads2830_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int ads7828_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct ads7828_platform_data *pdata = dev_get_platdata(dev);
+	struct ads7828_data *data;
+	struct device *hwmon_dev;
+	unsigned int vref_mv = ADS7828_INT_VREF_MV;
+	bool diff_input = false;
+	bool ext_vref = false;
+	unsigned int regval;
+
+	data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (pdata) {
+		diff_input = pdata->diff_input;
+		ext_vref = pdata->ext_vref;
+		if (ext_vref && pdata->vref_mv)
+			vref_mv = pdata->vref_mv;
+	}
+
+	/* Bound Vref with min/max values */
+	vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN,
+			    ADS7828_EXT_VREF_MV_MAX);
+
+	/* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
+	if (id->driver_data == ads7828) {
+		data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096);
+		data->regmap = devm_regmap_init_i2c(client,
+						    &ads2828_regmap_config);
+	} else {
+		data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 256);
+		data->regmap = devm_regmap_init_i2c(client,
+						    &ads2830_regmap_config);
+	}
+
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
+	if (!diff_input)
+		data->cmd_byte |= ADS7828_CMD_SD_SE;
+
+	/*
+	 * Datasheet specifies internal reference voltage is disabled by
+	 * default. The internal reference voltage needs to be enabled and
+	 * voltage needs to settle before getting valid ADC data. So perform a
+	 * dummy read to enable the internal reference voltage.
+	 */
+	if (!ext_vref)
+		regmap_read(data->regmap, data->cmd_byte, &regval);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   ads7828_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ads7828_device_ids[] = {
+	{ "ads7828", ads7828 },
+	{ "ads7830", ads7830 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
+
+static struct i2c_driver ads7828_driver = {
+	.driver = {
+		.name = "ads7828",
+	},
+
+	.id_table = ads7828_device_ids,
+	.probe = ads7828_probe,
+};
+
+module_i2c_driver(ads7828_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
+MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
new file mode 100644
index 0000000..4fd9e4d
--- /dev/null
+++ b/drivers/hwmon/ads7871.c
@@ -0,0 +1,250 @@
+/*
+ *  ads7871 - driver for TI ADS7871 A/D converter
+ *
+ *  Copyright (c) 2010 Paul Thomas <pthomas8589@gmail.com>
+ *
+ *  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.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  later as publishhed by the Free Software Foundation.
+ *
+ *	You need to have something like this in struct spi_board_info
+ *	{
+ *		.modalias	= "ads7871",
+ *		.max_speed_hz	= 2*1000*1000,
+ *		.chip_select	= 0,
+ *		.bus_num	= 1,
+ *	},
+ */
+
+/*From figure 18 in the datasheet*/
+/*Register addresses*/
+#define REG_LS_BYTE	0 /*A/D Output Data, LS Byte*/
+#define REG_MS_BYTE	1 /*A/D Output Data, MS Byte*/
+#define REG_PGA_VALID	2 /*PGA Valid Register*/
+#define REG_AD_CONTROL	3 /*A/D Control Register*/
+#define REG_GAIN_MUX	4 /*Gain/Mux Register*/
+#define REG_IO_STATE	5 /*Digital I/O State Register*/
+#define REG_IO_CONTROL	6 /*Digital I/O Control Register*/
+#define REG_OSC_CONTROL	7 /*Rev/Oscillator Control Register*/
+#define REG_SER_CONTROL 24 /*Serial Interface Control Register*/
+#define REG_ID		31 /*ID Register*/
+
+/*
+ * From figure 17 in the datasheet
+ * These bits get ORed with the address to form
+ * the instruction byte
+ */
+/*Instruction Bit masks*/
+#define INST_MODE_BM	(1 << 7)
+#define INST_READ_BM	(1 << 6)
+#define INST_16BIT_BM	(1 << 5)
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define MUX_CNV_BV	7
+#define MUX_CNV_BM	(1 << MUX_CNV_BV)
+#define MUX_M3_BM	(1 << 3) /*M3 selects single ended*/
+#define MUX_G_BV	4 /*allows for reg = (gain << MUX_G_BV) | ...*/
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define OSC_OSCR_BM	(1 << 5)
+#define OSC_OSCE_BM	(1 << 4)
+#define OSC_REFE_BM	(1 << 3)
+#define OSC_BUFE_BM	(1 << 2)
+#define OSC_R2V_BM	(1 << 1)
+#define OSC_RBG_BM	(1 << 0)
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define DEVICE_NAME	"ads7871"
+
+struct ads7871_data {
+	struct device	*hwmon_dev;
+	struct mutex	update_lock;
+};
+
+static int ads7871_read_reg8(struct spi_device *spi, int reg)
+{
+	int ret;
+	reg = reg | INST_READ_BM;
+	ret = spi_w8r8(spi, reg);
+	return ret;
+}
+
+static int ads7871_read_reg16(struct spi_device *spi, int reg)
+{
+	int ret;
+	reg = reg | INST_READ_BM | INST_16BIT_BM;
+	ret = spi_w8r16(spi, reg);
+	return ret;
+}
+
+static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
+{
+	u8 tmp[2] = {reg, val};
+	return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static ssize_t show_voltage(struct device *dev,
+		struct device_attribute *da, char *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int ret, val, i = 0;
+	uint8_t channel, mux_cnv;
+
+	channel = attr->index;
+	/*
+	 * TODO: add support for conversions
+	 * other than single ended with a gain of 1
+	 */
+	/*MUX_M3_BM forces single ended*/
+	/*This is also where the gain of the PGA would be set*/
+	ads7871_write_reg8(spi, REG_GAIN_MUX,
+		(MUX_CNV_BM | MUX_M3_BM | channel));
+
+	ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+	mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
+	/*
+	 * on 400MHz arm9 platform the conversion
+	 * is already done when we do this test
+	 */
+	while ((i < 2) && mux_cnv) {
+		i++;
+		ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+		mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
+		msleep_interruptible(1);
+	}
+
+	if (mux_cnv == 0) {
+		val = ads7871_read_reg16(spi, REG_LS_BYTE);
+		/*result in volts*10000 = (val/8192)*2.5*10000*/
+		val = ((val >> 2) * 25000) / 8192;
+		return sprintf(buf, "%d\n", val);
+	} else {
+		return -1;
+	}
+}
+
+static ssize_t ads7871_show_name(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
+
+static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL);
+
+static struct attribute *ads7871_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group ads7871_group = {
+	.attrs = ads7871_attributes,
+};
+
+static int ads7871_probe(struct spi_device *spi)
+{
+	int ret, err;
+	uint8_t val;
+	struct ads7871_data *pdata;
+
+	dev_dbg(&spi->dev, "probe\n");
+
+	/* Configure the SPI bus */
+	spi->mode = (SPI_MODE_0);
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
+	ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
+
+	val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
+	ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
+	ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
+
+	dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
+	/*
+	 * because there is no other error checking on an SPI bus
+	 * we need to make sure we really have a chip
+	 */
+	if (val != ret)
+		return -ENODEV;
+
+	pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data),
+			     GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	err = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
+	if (err < 0)
+		return err;
+
+	spi_set_drvdata(spi, pdata);
+
+	pdata->hwmon_dev = hwmon_device_register(&spi->dev);
+	if (IS_ERR(pdata->hwmon_dev)) {
+		err = PTR_ERR(pdata->hwmon_dev);
+		goto error_remove;
+	}
+
+	return 0;
+
+error_remove:
+	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+	return err;
+}
+
+static int ads7871_remove(struct spi_device *spi)
+{
+	struct ads7871_data *pdata = spi_get_drvdata(spi);
+
+	hwmon_device_unregister(pdata->hwmon_dev);
+	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+	return 0;
+}
+
+static struct spi_driver ads7871_driver = {
+	.driver = {
+		.name = DEVICE_NAME,
+	},
+
+	.probe = ads7871_probe,
+	.remove = ads7871_remove,
+};
+
+module_spi_driver(ads7871_driver);
+
+MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>");
+MODULE_DESCRIPTION("TI ADS7871 A/D driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
new file mode 100644
index 0000000..ec02f4f
--- /dev/null
+++ b/drivers/hwmon/adt7310.c
@@ -0,0 +1,117 @@
+/*
+ * ADT7310/ADT7310 digital temperature sensor driver
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
+
+#include "adt7x10.h"
+
+#define ADT7310_STATUS			0
+#define ADT7310_CONFIG			1
+#define ADT7310_TEMPERATURE		2
+#define ADT7310_ID			3
+#define ADT7310_T_CRIT			4
+#define ADT7310_T_HYST			5
+#define ADT7310_T_ALARM_HIGH		6
+#define ADT7310_T_ALARM_LOW		7
+
+static const u8 adt7310_reg_table[] = {
+	[ADT7X10_TEMPERATURE]   = ADT7310_TEMPERATURE,
+	[ADT7X10_STATUS]	= ADT7310_STATUS,
+	[ADT7X10_CONFIG]	= ADT7310_CONFIG,
+	[ADT7X10_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
+	[ADT7X10_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
+	[ADT7X10_T_CRIT]	= ADT7310_T_CRIT,
+	[ADT7X10_T_HYST]	= ADT7310_T_HYST,
+	[ADT7X10_ID]		= ADT7310_ID,
+};
+
+#define ADT7310_CMD_REG_OFFSET	3
+#define ADT7310_CMD_READ	0x40
+
+#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
+
+static int adt7310_spi_read_word(struct device *dev, u8 reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+}
+
+static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 buf[3];
+
+	buf[0] = AD7310_COMMAND(reg);
+	put_unaligned_be16(data, &buf[1]);
+
+	return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adt7310_spi_read_byte(struct device *dev, u8 reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+}
+
+static int adt7310_spi_write_byte(struct device *dev, u8 reg,
+	u8 data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 buf[2];
+
+	buf[0] = AD7310_COMMAND(reg);
+	buf[1] = data;
+
+	return spi_write(spi, buf, sizeof(buf));
+}
+
+static const struct adt7x10_ops adt7310_spi_ops = {
+	.read_word = adt7310_spi_read_word,
+	.write_word = adt7310_spi_write_word,
+	.read_byte = adt7310_spi_read_byte,
+	.write_byte = adt7310_spi_write_byte,
+};
+
+static int adt7310_spi_probe(struct spi_device *spi)
+{
+	return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
+			&adt7310_spi_ops);
+}
+
+static int adt7310_spi_remove(struct spi_device *spi)
+{
+	return adt7x10_remove(&spi->dev, spi->irq);
+}
+
+static const struct spi_device_id adt7310_id[] = {
+	{ "adt7310", 0 },
+	{ "adt7320", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+	.driver = {
+		.name	= "adt7310",
+		.pm	= ADT7X10_DEV_PM_OPS,
+	},
+	.probe		= adt7310_spi_probe,
+	.remove		= adt7310_spi_remove,
+	.id_table	= adt7310_id,
+};
+module_spi_driver(adt7310_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
new file mode 100644
index 0000000..0dc066a
--- /dev/null
+++ b/drivers/hwmon/adt7410.c
@@ -0,0 +1,80 @@
+/*
+ * ADT7410/ADT7420 digital temperature sensor driver
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include "adt7x10.h"
+
+static int adt7410_i2c_read_word(struct device *dev, u8 reg)
+{
+	return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
+}
+
+static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
+{
+	return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
+}
+
+static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
+{
+	return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
+}
+
+static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
+{
+	return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
+}
+
+static const struct adt7x10_ops adt7410_i2c_ops = {
+	.read_word = adt7410_i2c_read_word,
+	.write_word = adt7410_i2c_write_word,
+	.read_byte = adt7410_i2c_read_byte,
+	.write_byte = adt7410_i2c_write_byte,
+};
+
+static int adt7410_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
+}
+
+static int adt7410_i2c_remove(struct i2c_client *client)
+{
+	return adt7x10_remove(&client->dev, client->irq);
+}
+
+static const struct i2c_device_id adt7410_ids[] = {
+	{ "adt7410", 0 },
+	{ "adt7420", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
+static struct i2c_driver adt7410_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7410",
+		.pm	= ADT7X10_DEV_PM_OPS,
+	},
+	.probe		= adt7410_i2c_probe,
+	.remove		= adt7410_i2c_remove,
+	.id_table	= adt7410_ids,
+	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
+};
+module_i2c_driver(adt7410_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7410/AD7420 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
new file mode 100644
index 0000000..a7f8869
--- /dev/null
+++ b/drivers/hwmon/adt7411.c
@@ -0,0 +1,338 @@
+/*
+ *  Driver for the ADT7411 (I2C/SPI 8 channel 10 bit ADC & temperature-sensor)
+ *
+ *  Copyright (C) 2008, 2010 Pengutronix
+ *
+ *  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.
+ *
+ *  TODO: SPI, support for external temperature sensor
+ *	  use power-down mode for suspend?, interrupt handling?
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/slab.h>
+
+#define ADT7411_REG_INT_TEMP_VDD_LSB		0x03
+#define ADT7411_REG_EXT_TEMP_AIN14_LSB		0x04
+#define ADT7411_REG_VDD_MSB			0x06
+#define ADT7411_REG_INT_TEMP_MSB		0x07
+#define ADT7411_REG_EXT_TEMP_AIN1_MSB		0x08
+
+#define ADT7411_REG_CFG1			0x18
+#define ADT7411_CFG1_START_MONITOR		(1 << 0)
+#define ADT7411_CFG1_RESERVED_BIT3		(1 << 3)
+
+#define ADT7411_REG_CFG2			0x19
+#define ADT7411_CFG2_DISABLE_AVG		(1 << 5)
+
+#define ADT7411_REG_CFG3			0x1a
+#define ADT7411_CFG3_ADC_CLK_225		(1 << 0)
+#define ADT7411_CFG3_REF_VDD			(1 << 4)
+
+#define ADT7411_REG_DEVICE_ID			0x4d
+#define ADT7411_REG_MANUFACTURER_ID		0x4e
+
+#define ADT7411_DEVICE_ID			0x2
+#define ADT7411_MANUFACTURER_ID			0x41
+
+static const unsigned short normal_i2c[] = { 0x48, 0x4a, 0x4b, I2C_CLIENT_END };
+
+struct adt7411_data {
+	struct mutex device_lock;	/* for "atomic" device accesses */
+	struct mutex update_lock;
+	unsigned long next_update;
+	int vref_cached;
+	struct i2c_client *client;
+};
+
+/*
+ * When reading a register containing (up to 4) lsb, all associated
+ * msb-registers get locked by the hardware. After _one_ of those msb is read,
+ * _all_ are unlocked. In order to use this locking correctly, reading lsb/msb
+ * is protected here with a mutex, too.
+ */
+static int adt7411_read_10_bit(struct i2c_client *client, u8 lsb_reg,
+				u8 msb_reg, u8 lsb_shift)
+{
+	struct adt7411_data *data = i2c_get_clientdata(client);
+	int val, tmp;
+
+	mutex_lock(&data->device_lock);
+
+	val = i2c_smbus_read_byte_data(client, lsb_reg);
+	if (val < 0)
+		goto exit_unlock;
+
+	tmp = (val >> lsb_shift) & 3;
+	val = i2c_smbus_read_byte_data(client, msb_reg);
+
+	if (val >= 0)
+		val = (val << 2) | tmp;
+
+ exit_unlock:
+	mutex_unlock(&data->device_lock);
+
+	return val;
+}
+
+static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit,
+				bool flag)
+{
+	struct adt7411_data *data = i2c_get_clientdata(client);
+	int ret, val;
+
+	mutex_lock(&data->device_lock);
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret < 0)
+		goto exit_unlock;
+
+	if (flag)
+		val = ret | bit;
+	else
+		val = ret & ~bit;
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+
+ exit_unlock:
+	mutex_unlock(&data->device_lock);
+	return ret;
+}
+
+static ssize_t adt7411_show_vdd(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct adt7411_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
+			ADT7411_REG_VDD_MSB, 2);
+
+	return ret < 0 ? ret : sprintf(buf, "%u\n", ret * 7000 / 1024);
+}
+
+static ssize_t adt7411_show_temp(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct adt7411_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int val = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
+			ADT7411_REG_INT_TEMP_MSB, 0);
+
+	if (val < 0)
+		return val;
+
+	val = val & 0x200 ? val - 0x400 : val; /* 10 bit signed */
+
+	return sprintf(buf, "%d\n", val * 250);
+}
+
+static ssize_t adt7411_show_input(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct adt7411_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int val;
+	u8 lsb_reg, lsb_shift;
+
+	mutex_lock(&data->update_lock);
+	if (time_after_eq(jiffies, data->next_update)) {
+		val = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3);
+		if (val < 0)
+			goto exit_unlock;
+
+		if (val & ADT7411_CFG3_REF_VDD) {
+			val = adt7411_read_10_bit(client,
+					ADT7411_REG_INT_TEMP_VDD_LSB,
+					ADT7411_REG_VDD_MSB, 2);
+			if (val < 0)
+				goto exit_unlock;
+
+			data->vref_cached = val * 7000 / 1024;
+		} else {
+			data->vref_cached = 2250;
+		}
+
+		data->next_update = jiffies + HZ;
+	}
+
+	lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2);
+	lsb_shift = 2 * (nr & 0x03);
+	val = adt7411_read_10_bit(client, lsb_reg,
+			ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, lsb_shift);
+	if (val < 0)
+		goto exit_unlock;
+
+	val = sprintf(buf, "%u\n", val * data->vref_cached / 1024);
+ exit_unlock:
+	mutex_unlock(&data->update_lock);
+	return val;
+}
+
+static ssize_t adt7411_show_bit(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+	struct adt7411_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret = i2c_smbus_read_byte_data(client, attr2->index);
+
+	return ret < 0 ? ret : sprintf(buf, "%u\n", !!(ret & attr2->nr));
+}
+
+static ssize_t adt7411_set_bit(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	struct sensor_device_attribute_2 *s_attr2 = to_sensor_dev_attr_2(attr);
+	struct adt7411_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret;
+	unsigned long flag;
+
+	ret = kstrtoul(buf, 0, &flag);
+	if (ret || flag > 1)
+		return -EINVAL;
+
+	ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag);
+
+	/* force update */
+	mutex_lock(&data->update_lock);
+	data->next_update = jiffies;
+	mutex_unlock(&data->update_lock);
+
+	return ret < 0 ? ret : count;
+}
+
+#define ADT7411_BIT_ATTR(__name, __reg, __bit) \
+	SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \
+	adt7411_set_bit, __bit, __reg)
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL);
+static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, adt7411_show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, adt7411_show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, adt7411_show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, adt7411_show_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, adt7411_show_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, adt7411_show_input, NULL, 7);
+static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG);
+static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225);
+static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD);
+
+static struct attribute *adt7411_attrs[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_in0_input.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_no_average.dev_attr.attr,
+	&sensor_dev_attr_fast_sampling.dev_attr.attr,
+	&sensor_dev_attr_adc_ref_vdd.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(adt7411);
+
+static int adt7411_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	int val;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
+	if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
+		dev_dbg(&client->dev,
+			"Wrong manufacturer ID. Got %d, expected %d\n",
+			val, ADT7411_MANUFACTURER_ID);
+		return -ENODEV;
+	}
+
+	val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
+	if (val < 0 || val != ADT7411_DEVICE_ID) {
+		dev_dbg(&client->dev,
+			"Wrong device ID. Got %d, expected %d\n",
+			val, ADT7411_DEVICE_ID);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "adt7411", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int adt7411_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct adt7411_data *data;
+	struct device *hwmon_dev;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->device_lock);
+	mutex_init(&data->update_lock);
+
+	/* According to the datasheet, we must only write 1 to bit 3 */
+	ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
+				 ADT7411_CFG1_RESERVED_BIT3
+				 | ADT7411_CFG1_START_MONITOR, 1);
+	if (ret < 0)
+		return ret;
+
+	/* force update on first occasion */
+	data->next_update = jiffies;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   adt7411_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adt7411_id[] = {
+	{ "adt7411", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7411_id);
+
+static struct i2c_driver adt7411_driver = {
+	.driver		= {
+		.name		= "adt7411",
+	},
+	.probe  = adt7411_probe,
+	.id_table = adt7411_id,
+	.detect = adt7411_detect,
+	.address_list = normal_i2c,
+	.class = I2C_CLASS_HWMON,
+};
+
+module_i2c_driver(adt7411_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de> and "
+	"Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("ADT7411 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
new file mode 100644
index 0000000..5929e12
--- /dev/null
+++ b/drivers/hwmon/adt7462.c
@@ -0,0 +1,1946 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7462
+ * Copyright (C) 2008 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.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/log2.h>
+#include <linux/slab.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
+
+/* ADT7462 registers */
+#define ADT7462_REG_DEVICE			0x3D
+#define ADT7462_REG_VENDOR			0x3E
+#define ADT7462_REG_REVISION			0x3F
+
+#define ADT7462_REG_MIN_TEMP_BASE_ADDR		0x44
+#define ADT7462_REG_MIN_TEMP_MAX_ADDR		0x47
+#define ADT7462_REG_MAX_TEMP_BASE_ADDR		0x48
+#define ADT7462_REG_MAX_TEMP_MAX_ADDR		0x4B
+#define ADT7462_REG_TEMP_BASE_ADDR		0x88
+#define ADT7462_REG_TEMP_MAX_ADDR		0x8F
+
+#define ADT7462_REG_FAN_BASE_ADDR		0x98
+#define ADT7462_REG_FAN_MAX_ADDR		0x9F
+#define ADT7462_REG_FAN2_BASE_ADDR		0xA2
+#define ADT7462_REG_FAN2_MAX_ADDR		0xA9
+#define ADT7462_REG_FAN_ENABLE			0x07
+#define ADT7462_REG_FAN_MIN_BASE_ADDR		0x78
+#define ADT7462_REG_FAN_MIN_MAX_ADDR		0x7F
+
+#define ADT7462_REG_CFG2			0x02
+#define		ADT7462_FSPD_MASK		0x20
+
+#define ADT7462_REG_PWM_BASE_ADDR		0xAA
+#define ADT7462_REG_PWM_MAX_ADDR		0xAD
+#define	ADT7462_REG_PWM_MIN_BASE_ADDR		0x28
+#define ADT7462_REG_PWM_MIN_MAX_ADDR		0x2B
+#define ADT7462_REG_PWM_MAX			0x2C
+#define ADT7462_REG_PWM_TEMP_MIN_BASE_ADDR	0x5C
+#define ADT7462_REG_PWM_TEMP_MIN_MAX_ADDR	0x5F
+#define ADT7462_REG_PWM_TEMP_RANGE_BASE_ADDR	0x60
+#define ADT7462_REG_PWM_TEMP_RANGE_MAX_ADDR	0x63
+#define	ADT7462_PWM_HYST_MASK			0x0F
+#define	ADT7462_PWM_RANGE_MASK			0xF0
+#define		ADT7462_PWM_RANGE_SHIFT		4
+#define ADT7462_REG_PWM_CFG_BASE_ADDR		0x21
+#define ADT7462_REG_PWM_CFG_MAX_ADDR		0x24
+#define		ADT7462_PWM_CHANNEL_MASK	0xE0
+#define		ADT7462_PWM_CHANNEL_SHIFT	5
+
+#define ADT7462_REG_PIN_CFG_BASE_ADDR		0x10
+#define ADT7462_REG_PIN_CFG_MAX_ADDR		0x13
+#define		ADT7462_PIN7_INPUT		0x01	/* cfg0 */
+#define		ADT7462_DIODE3_INPUT		0x20
+#define		ADT7462_DIODE1_INPUT		0x40
+#define		ADT7462_VID_INPUT		0x80
+#define		ADT7462_PIN22_INPUT		0x04	/* cfg1 */
+#define		ADT7462_PIN21_INPUT		0x08
+#define		ADT7462_PIN19_INPUT		0x10
+#define		ADT7462_PIN15_INPUT		0x20
+#define		ADT7462_PIN13_INPUT		0x40
+#define		ADT7462_PIN8_INPUT		0x80
+#define		ADT7462_PIN23_MASK		0x03
+#define		ADT7462_PIN23_SHIFT		0
+#define		ADT7462_PIN26_MASK		0x0C	/* cfg2 */
+#define		ADT7462_PIN26_SHIFT		2
+#define		ADT7462_PIN25_MASK		0x30
+#define		ADT7462_PIN25_SHIFT		4
+#define		ADT7462_PIN24_MASK		0xC0
+#define		ADT7462_PIN24_SHIFT		6
+#define		ADT7462_PIN26_VOLT_INPUT	0x08
+#define		ADT7462_PIN25_VOLT_INPUT	0x20
+#define		ADT7462_PIN28_SHIFT		4	/* cfg3 */
+#define		ADT7462_PIN28_VOLT		0x5
+
+#define ADT7462_REG_ALARM1			0xB8
+#define	ADT7462_LT_ALARM			0x02
+#define		ADT7462_R1T_ALARM		0x04
+#define		ADT7462_R2T_ALARM		0x08
+#define		ADT7462_R3T_ALARM		0x10
+#define ADT7462_REG_ALARM2			0xBB
+#define		ADT7462_V0_ALARM		0x01
+#define		ADT7462_V1_ALARM		0x02
+#define		ADT7462_V2_ALARM		0x04
+#define		ADT7462_V3_ALARM		0x08
+#define		ADT7462_V4_ALARM		0x10
+#define		ADT7462_V5_ALARM		0x20
+#define		ADT7462_V6_ALARM		0x40
+#define		ADT7462_V7_ALARM		0x80
+#define ADT7462_REG_ALARM3			0xBC
+#define		ADT7462_V8_ALARM		0x08
+#define		ADT7462_V9_ALARM		0x10
+#define		ADT7462_V10_ALARM		0x20
+#define		ADT7462_V11_ALARM		0x40
+#define		ADT7462_V12_ALARM		0x80
+#define ADT7462_REG_ALARM4			0xBD
+#define		ADT7462_F0_ALARM		0x01
+#define		ADT7462_F1_ALARM		0x02
+#define		ADT7462_F2_ALARM		0x04
+#define		ADT7462_F3_ALARM		0x08
+#define		ADT7462_F4_ALARM		0x10
+#define		ADT7462_F5_ALARM		0x20
+#define		ADT7462_F6_ALARM		0x40
+#define		ADT7462_F7_ALARM		0x80
+#define ADT7462_ALARM1				0x0000
+#define ADT7462_ALARM2				0x0100
+#define ADT7462_ALARM3				0x0200
+#define ADT7462_ALARM4				0x0300
+#define ADT7462_ALARM_REG_SHIFT			8
+#define ADT7462_ALARM_FLAG_MASK			0x0F
+
+#define ADT7462_TEMP_COUNT		4
+#define ADT7462_TEMP_REG(x)		(ADT7462_REG_TEMP_BASE_ADDR + ((x) * 2))
+#define ADT7462_TEMP_MIN_REG(x)		(ADT7462_REG_MIN_TEMP_BASE_ADDR + (x))
+#define ADT7462_TEMP_MAX_REG(x)		(ADT7462_REG_MAX_TEMP_BASE_ADDR + (x))
+#define TEMP_FRAC_OFFSET		6
+
+#define ADT7462_FAN_COUNT		8
+#define ADT7462_REG_FAN_MIN(x)		(ADT7462_REG_FAN_MIN_BASE_ADDR + (x))
+
+#define ADT7462_PWM_COUNT		4
+#define ADT7462_REG_PWM(x)		(ADT7462_REG_PWM_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_MIN(x)		(ADT7462_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_TMIN(x)		\
+	(ADT7462_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_TRANGE(x)	\
+	(ADT7462_REG_PWM_TEMP_RANGE_BASE_ADDR + (x))
+
+#define ADT7462_PIN_CFG_REG_COUNT	4
+#define ADT7462_REG_PIN_CFG(x)		(ADT7462_REG_PIN_CFG_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_CFG(x)		(ADT7462_REG_PWM_CFG_BASE_ADDR + (x))
+
+#define ADT7462_ALARM_REG_COUNT		4
+
+/*
+ * The chip can measure 13 different voltage sources:
+ *
+ * 1. +12V1 (pin 7)
+ * 2. Vccp1/+2.5V/+1.8V/+1.5V (pin 23)
+ * 3. +12V3 (pin 22)
+ * 4. +5V (pin 21)
+ * 5. +1.25V/+0.9V (pin 19)
+ * 6. +2.5V/+1.8V (pin 15)
+ * 7. +3.3v (pin 13)
+ * 8. +12V2 (pin 8)
+ * 9. Vbatt/FSB_Vtt (pin 26)
+ * A. +3.3V/+1.2V1 (pin 25)
+ * B. Vccp2/+2.5V/+1.8V/+1.5V (pin 24)
+ * C. +1.5V ICH (only if BOTH pin 28/29 are set to +1.5V)
+ * D. +1.5V 3GPIO (only if BOTH pin 28/29 are set to +1.5V)
+ *
+ * Each of these 13 has a factor to convert raw to voltage.  Even better,
+ * the pins can be connected to other sensors (tach/gpio/hot/etc), which
+ * makes the bookkeeping tricky.
+ *
+ * Some, but not all, of these voltages have low/high limits.
+ */
+#define ADT7462_VOLT_COUNT	13
+
+#define ADT7462_VENDOR		0x41
+#define ADT7462_DEVICE		0x62
+/* datasheet only mentions a revision 4 */
+#define ADT7462_REVISION	0x04
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL	(2 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL	(60 * HZ)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID	65535
+#define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
+
+#define MASK_AND_SHIFT(value, prefix)	\
+	(((value) & prefix##_MASK) >> prefix##_SHIFT)
+
+struct adt7462_data {
+	struct i2c_client	*client;
+	struct mutex		lock;
+	char			sensors_valid;
+	char			limits_valid;
+	unsigned long		sensors_last_updated;	/* In jiffies */
+	unsigned long		limits_last_updated;	/* In jiffies */
+
+	u8			temp[ADT7462_TEMP_COUNT];
+				/* bits 6-7 are quarter pieces of temp */
+	u8			temp_frac[ADT7462_TEMP_COUNT];
+	u8			temp_min[ADT7462_TEMP_COUNT];
+	u8			temp_max[ADT7462_TEMP_COUNT];
+	u16			fan[ADT7462_FAN_COUNT];
+	u8			fan_enabled;
+	u8			fan_min[ADT7462_FAN_COUNT];
+	u8			cfg2;
+	u8			pwm[ADT7462_PWM_COUNT];
+	u8			pin_cfg[ADT7462_PIN_CFG_REG_COUNT];
+	u8			voltages[ADT7462_VOLT_COUNT];
+	u8			volt_max[ADT7462_VOLT_COUNT];
+	u8			volt_min[ADT7462_VOLT_COUNT];
+	u8			pwm_min[ADT7462_PWM_COUNT];
+	u8			pwm_tmin[ADT7462_PWM_COUNT];
+	u8			pwm_trange[ADT7462_PWM_COUNT];
+	u8			pwm_max;	/* only one per chip */
+	u8			pwm_cfg[ADT7462_PWM_COUNT];
+	u8			alarms[ADT7462_ALARM_REG_COUNT];
+};
+
+/*
+ * 16-bit registers on the ADT7462 are low-byte first.  The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7462_read_word_data(struct i2c_client *client, u8 reg)
+{
+	u16 foo;
+	foo = i2c_smbus_read_byte_data(client, reg);
+	foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+	return foo;
+}
+
+/* For some reason these registers are not contiguous. */
+static int ADT7462_REG_FAN(int fan)
+{
+	if (fan < 4)
+		return ADT7462_REG_FAN_BASE_ADDR + (2 * fan);
+	return ADT7462_REG_FAN2_BASE_ADDR + (2 * (fan - 4));
+}
+
+/* Voltage registers are scattered everywhere */
+static int ADT7462_REG_VOLT_MAX(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+			return 0x7C;
+		break;
+	case 1:
+		return 0x69;
+	case 2:
+		if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+			return 0x7F;
+		break;
+	case 3:
+		if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+			return 0x7E;
+		break;
+	case 4:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+			return 0x4B;
+		break;
+	case 5:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+			return 0x49;
+		break;
+	case 6:
+		if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+			return 0x68;
+		break;
+	case 7:
+		if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+			return 0x7D;
+		break;
+	case 8:
+		if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+			return 0x6C;
+		break;
+	case 9:
+		if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+			return 0x6B;
+		break;
+	case 10:
+		return 0x6A;
+	case 11:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x50;
+		break;
+	case 12:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x4C;
+		break;
+	}
+	return 0;
+}
+
+static int ADT7462_REG_VOLT_MIN(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+			return 0x6D;
+		break;
+	case 1:
+		return 0x72;
+	case 2:
+		if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+			return 0x6F;
+		break;
+	case 3:
+		if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+			return 0x71;
+		break;
+	case 4:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+			return 0x47;
+		break;
+	case 5:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+			return 0x45;
+		break;
+	case 6:
+		if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+			return 0x70;
+		break;
+	case 7:
+		if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+			return 0x6E;
+		break;
+	case 8:
+		if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+			return 0x75;
+		break;
+	case 9:
+		if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+			return 0x74;
+		break;
+	case 10:
+		return 0x73;
+	case 11:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x76;
+		break;
+	case 12:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x77;
+		break;
+	}
+	return 0;
+}
+
+static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+			return 0xA3;
+		break;
+	case 1:
+		return 0x90;
+	case 2:
+		if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+			return 0xA9;
+		break;
+	case 3:
+		if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+			return 0xA7;
+		break;
+	case 4:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+			return 0x8F;
+		break;
+	case 5:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+			return 0x8B;
+		break;
+	case 6:
+		if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+			return 0x96;
+		break;
+	case 7:
+		if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+			return 0xA5;
+		break;
+	case 8:
+		if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+			return 0x93;
+		break;
+	case 9:
+		if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+			return 0x92;
+		break;
+	case 10:
+		return 0x91;
+	case 11:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x94;
+		break;
+	case 12:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 0x95;
+		break;
+	}
+	return -ENODEV;
+}
+
+/* Provide labels for sysfs */
+static const char *voltage_label(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+			return "+12V1";
+		break;
+	case 1:
+		switch (MASK_AND_SHIFT(data->pin_cfg[1], ADT7462_PIN23)) {
+		case 0:
+			return "Vccp1";
+		case 1:
+			return "+2.5V";
+		case 2:
+			return "+1.8V";
+		case 3:
+			return "+1.5V";
+		}
+	case 2:
+		if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+			return "+12V3";
+		break;
+	case 3:
+		if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+			return "+5V";
+		break;
+	case 4:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT)) {
+			if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+				return "+0.9V";
+			return "+1.25V";
+		}
+		break;
+	case 5:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT)) {
+			if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+				return "+1.8V";
+			return "+2.5V";
+		}
+		break;
+	case 6:
+		if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+			return "+3.3V";
+		break;
+	case 7:
+		if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+			return "+12V2";
+		break;
+	case 8:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN26)) {
+		case 0:
+			return "Vbatt";
+		case 1:
+			return "FSB_Vtt";
+		}
+		break;
+	case 9:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN25)) {
+		case 0:
+			return "+3.3V";
+		case 1:
+			return "+1.2V1";
+		}
+		break;
+	case 10:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN24)) {
+		case 0:
+			return "Vccp2";
+		case 1:
+			return "+2.5V";
+		case 2:
+			return "+1.8V";
+		case 3:
+			return "+1.5";
+		}
+	case 11:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return "+1.5V ICH";
+		break;
+	case 12:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return "+1.5V 3GPIO";
+		break;
+	}
+	return "N/A";
+}
+
+/* Multipliers are actually in uV, not mV. */
+static int voltage_multiplier(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+			return 62500;
+		break;
+	case 1:
+		switch (MASK_AND_SHIFT(data->pin_cfg[1], ADT7462_PIN23)) {
+		case 0:
+			if (data->pin_cfg[0] & ADT7462_VID_INPUT)
+				return 12500;
+			return 6250;
+		case 1:
+			return 13000;
+		case 2:
+			return 9400;
+		case 3:
+			return 7800;
+		}
+	case 2:
+		if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+			return 62500;
+		break;
+	case 3:
+		if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+			return 26000;
+		break;
+	case 4:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT)) {
+			if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+				return 4690;
+			return 6500;
+		}
+		break;
+	case 5:
+		if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT)) {
+			if (data->pin_cfg[1] & ADT7462_PIN15_INPUT)
+				return 9400;
+			return 13000;
+		}
+		break;
+	case 6:
+		if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+			return 17200;
+		break;
+	case 7:
+		if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+			return 62500;
+		break;
+	case 8:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN26)) {
+		case 0:
+			return 15600;
+		case 1:
+			return 6250;
+		}
+		break;
+	case 9:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN25)) {
+		case 0:
+			return 17200;
+		case 1:
+			return 6250;
+		}
+		break;
+	case 10:
+		switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN24)) {
+		case 0:
+			return 6250;
+		case 1:
+			return 13000;
+		case 2:
+			return 9400;
+		case 3:
+			return 7800;
+		}
+	case 11:
+	case 12:
+		if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+					ADT7462_PIN28_VOLT &&
+		    !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+			return 7800;
+	}
+	return 0;
+}
+
+static int temp_enabled(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+	case 2:
+		return 1;
+	case 1:
+		if (data->pin_cfg[0] & ADT7462_DIODE1_INPUT)
+			return 1;
+		break;
+	case 3:
+		if (data->pin_cfg[0] & ADT7462_DIODE3_INPUT)
+			return 1;
+		break;
+	}
+	return 0;
+}
+
+static const char *temp_label(struct adt7462_data *data, int which)
+{
+	switch (which) {
+	case 0:
+		return "local";
+	case 1:
+		if (data->pin_cfg[0] & ADT7462_DIODE1_INPUT)
+			return "remote1";
+		break;
+	case 2:
+		return "remote2";
+	case 3:
+		if (data->pin_cfg[0] & ADT7462_DIODE3_INPUT)
+			return "remote3";
+		break;
+	}
+	return "N/A";
+}
+
+/* Map Trange register values to mC */
+#define NUM_TRANGE_VALUES	16
+static const int trange_values[NUM_TRANGE_VALUES] = {
+	2000,
+	2500,
+	3300,
+	4000,
+	5000,
+	6700,
+	8000,
+	10000,
+	13300,
+	16000,
+	20000,
+	26700,
+	32000,
+	40000,
+	53300,
+	80000
+};
+
+static int find_trange_value(int trange)
+{
+	int i;
+
+	for (i = 0; i < NUM_TRANGE_VALUES; i++)
+		if (trange_values[i] == trange)
+			return i;
+
+	return -EINVAL;
+}
+
+static struct adt7462_data *adt7462_update_device(struct device *dev)
+{
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long local_jiffies = jiffies;
+	int i;
+
+	mutex_lock(&data->lock);
+	if (time_before(local_jiffies, data->sensors_last_updated +
+		SENSOR_REFRESH_INTERVAL)
+		&& data->sensors_valid)
+		goto no_sensor_update;
+
+	for (i = 0; i < ADT7462_TEMP_COUNT; i++) {
+		/*
+		 * Reading the fractional register locks the integral
+		 * register until both have been read.
+		 */
+		data->temp_frac[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_TEMP_REG(i));
+		data->temp[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_TEMP_REG(i) + 1);
+	}
+
+	for (i = 0; i < ADT7462_FAN_COUNT; i++)
+		data->fan[i] = adt7462_read_word_data(client,
+						ADT7462_REG_FAN(i));
+
+	data->fan_enabled = i2c_smbus_read_byte_data(client,
+					ADT7462_REG_FAN_ENABLE);
+
+	for (i = 0; i < ADT7462_PWM_COUNT; i++)
+		data->pwm[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_PWM(i));
+
+	for (i = 0; i < ADT7462_PIN_CFG_REG_COUNT; i++)
+		data->pin_cfg[i] = i2c_smbus_read_byte_data(client,
+				ADT7462_REG_PIN_CFG(i));
+
+	for (i = 0; i < ADT7462_VOLT_COUNT; i++) {
+		int reg = ADT7462_REG_VOLT(data, i);
+		if (!reg)
+			data->voltages[i] = 0;
+		else
+			data->voltages[i] = i2c_smbus_read_byte_data(client,
+								     reg);
+	}
+
+	data->alarms[0] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM1);
+	data->alarms[1] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM2);
+	data->alarms[2] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM3);
+	data->alarms[3] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM4);
+
+	data->sensors_last_updated = local_jiffies;
+	data->sensors_valid = 1;
+
+no_sensor_update:
+	if (time_before(local_jiffies, data->limits_last_updated +
+		LIMIT_REFRESH_INTERVAL)
+		&& data->limits_valid)
+		goto out;
+
+	for (i = 0; i < ADT7462_TEMP_COUNT; i++) {
+		data->temp_min[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_TEMP_MIN_REG(i));
+		data->temp_max[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_TEMP_MAX_REG(i));
+	}
+
+	for (i = 0; i < ADT7462_FAN_COUNT; i++)
+		data->fan_min[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_FAN_MIN(i));
+
+	for (i = 0; i < ADT7462_VOLT_COUNT; i++) {
+		int reg = ADT7462_REG_VOLT_MAX(data, i);
+		data->volt_max[i] =
+			(reg ? i2c_smbus_read_byte_data(client, reg) : 0);
+
+		reg = ADT7462_REG_VOLT_MIN(data, i);
+		data->volt_min[i] =
+			(reg ? i2c_smbus_read_byte_data(client, reg) : 0);
+	}
+
+	for (i = 0; i < ADT7462_PWM_COUNT; i++) {
+		data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_PWM_MIN(i));
+		data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_PWM_TMIN(i));
+		data->pwm_trange[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_PWM_TRANGE(i));
+		data->pwm_cfg[i] = i2c_smbus_read_byte_data(client,
+						ADT7462_REG_PWM_CFG(i));
+	}
+
+	data->pwm_max = i2c_smbus_read_byte_data(client, ADT7462_REG_PWM_MAX);
+
+	data->cfg2 = i2c_smbus_read_byte_data(client, ADT7462_REG_CFG2);
+
+	data->limits_last_updated = local_jiffies;
+	data->limits_valid = 1;
+
+out:
+	mutex_unlock(&data->lock);
+	return data;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	if (!temp_enabled(data, attr->index))
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d\n", 1000 * (data->temp_min[attr->index] - 64));
+}
+
+static ssize_t set_temp_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->temp_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_TEMP_MIN_REG(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	if (!temp_enabled(data, attr->index))
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d\n", 1000 * (data->temp_max[attr->index] - 64));
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->temp_max[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_TEMP_MAX_REG(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+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 adt7462_data *data = adt7462_update_device(dev);
+	u8 frac = data->temp_frac[attr->index] >> TEMP_FRAC_OFFSET;
+
+	if (!temp_enabled(data, attr->index))
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d\n", 1000 * (data->temp[attr->index] - 64) +
+				     250 * frac);
+}
+
+static ssize_t show_temp_label(struct device *dev,
+			       struct device_attribute *devattr,
+			       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	return sprintf(buf, "%s\n", temp_label(data, attr->index));
+}
+
+static ssize_t show_volt_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int x = voltage_multiplier(data, attr->index);
+
+	x *= data->volt_max[attr->index];
+	x /= 1000; /* convert from uV to mV */
+
+	return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t set_volt_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int x = voltage_multiplier(data, attr->index);
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !x)
+		return -EINVAL;
+
+	temp *= 1000; /* convert mV to uV */
+	temp = DIV_ROUND_CLOSEST(temp, x);
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->volt_max[attr->index] = temp;
+	i2c_smbus_write_byte_data(client,
+				  ADT7462_REG_VOLT_MAX(data, attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_volt_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int x = voltage_multiplier(data, attr->index);
+
+	x *= data->volt_min[attr->index];
+	x /= 1000; /* convert from uV to mV */
+
+	return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t set_volt_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int x = voltage_multiplier(data, attr->index);
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !x)
+		return -EINVAL;
+
+	temp *= 1000; /* convert mV to uV */
+	temp = DIV_ROUND_CLOSEST(temp, x);
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->volt_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client,
+				  ADT7462_REG_VOLT_MIN(data, attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_voltage(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int x = voltage_multiplier(data, attr->index);
+
+	x *= data->voltages[attr->index];
+	x /= 1000; /* convert from uV to mV */
+
+	return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t show_voltage_label(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	return sprintf(buf, "%s\n", voltage_label(data, attr->index));
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int reg = attr->index >> ADT7462_ALARM_REG_SHIFT;
+	int mask = attr->index & ADT7462_ALARM_FLAG_MASK;
+
+	if (data->alarms[reg] & mask)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static int fan_enabled(struct adt7462_data *data, int fan)
+{
+	return data->fan_enabled & (1 << fan);
+}
+
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	u16 temp;
+
+	/* Only the MSB of the min fan period is stored... */
+	temp = data->fan_min[attr->index];
+	temp <<= 8;
+
+	if (!fan_enabled(data, attr->index) ||
+	    !FAN_DATA_VALID(temp))
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d\n", FAN_PERIOD_TO_RPM(temp));
+}
+
+static ssize_t set_fan_min(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !temp ||
+	    !fan_enabled(data, attr->index))
+		return -EINVAL;
+
+	temp = FAN_RPM_TO_PERIOD(temp);
+	temp >>= 8;
+	temp = clamp_val(temp, 1, 255);
+
+	mutex_lock(&data->lock);
+	data->fan_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_FAN_MIN(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	if (!fan_enabled(data, attr->index) ||
+	    !FAN_DATA_VALID(data->fan[attr->index]))
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d\n",
+		       FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", (data->cfg2 & ADT7462_FSPD_MASK ? 1 : 0));
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+				 struct device_attribute *devattr,
+				 const char *buf,
+				 size_t count)
+{
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	u8 reg;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	reg = i2c_smbus_read_byte_data(client, ADT7462_REG_CFG2);
+	if (temp)
+		reg |= ADT7462_FSPD_MASK;
+	else
+		reg &= ~ADT7462_FSPD_MASK;
+	data->cfg2 = reg;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_CFG2, reg);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM(attr->index), temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_max);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf,
+			   size_t count)
+{
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm_max = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_MAX, temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf,
+			   size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_MIN(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_hyst(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 *
+		      (data->pwm_trange[attr->index] & ADT7462_PWM_HYST_MASK));
+}
+
+static ssize_t set_pwm_hyst(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+	temp = clamp_val(temp, 0, 15);
+
+	/* package things up */
+	temp &= ADT7462_PWM_HYST_MASK;
+	temp |= data->pwm_trange[attr->index] & ADT7462_PWM_RANGE_MASK;
+
+	mutex_lock(&data->lock);
+	data->pwm_trange[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TRANGE(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+
+	/* tmax = tmin + trange */
+	int trange = trange_values[data->pwm_trange[attr->index] >>
+				   ADT7462_PWM_RANGE_SHIFT];
+	int tmin = (data->pwm_tmin[attr->index] - 64) * 1000;
+
+	return sprintf(buf, "%d\n", tmin + trange);
+}
+
+static ssize_t set_pwm_tmax(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	int temp;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int tmin, trange_value;
+	long trange;
+
+	if (kstrtol(buf, 10, &trange))
+		return -EINVAL;
+
+	/* trange = tmax - tmin */
+	tmin = (data->pwm_tmin[attr->index] - 64) * 1000;
+	trange_value = find_trange_value(trange - tmin);
+	if (trange_value < 0)
+		return trange_value;
+
+	temp = trange_value << ADT7462_PWM_RANGE_SHIFT;
+	temp |= data->pwm_trange[attr->index] & ADT7462_PWM_HYST_MASK;
+
+	mutex_lock(&data->lock);
+	data->pwm_trange[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TRANGE(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 * (data->pwm_tmin[attr->index] - 64));
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm_tmin[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TMIN(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int cfg = data->pwm_cfg[attr->index] >> ADT7462_PWM_CHANNEL_SHIFT;
+
+	switch (cfg) {
+	case 4: /* off */
+		return sprintf(buf, "0\n");
+	case 7: /* manual */
+		return sprintf(buf, "1\n");
+	default: /* automatic */
+		return sprintf(buf, "2\n");
+	}
+}
+
+static void set_pwm_channel(struct i2c_client *client,
+			    struct adt7462_data *data,
+			    int which,
+			    int value)
+{
+	int temp = data->pwm_cfg[which] & ~ADT7462_PWM_CHANNEL_MASK;
+	temp |= value << ADT7462_PWM_CHANNEL_SHIFT;
+
+	mutex_lock(&data->lock);
+	data->pwm_cfg[which] = temp;
+	i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_CFG(which), temp);
+	mutex_unlock(&data->lock);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	switch (temp) {
+	case 0: /* off */
+		set_pwm_channel(client, data, attr->index, 4);
+		return count;
+	case 1: /* manual */
+		set_pwm_channel(client, data, attr->index, 7);
+		return count;
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = adt7462_update_device(dev);
+	int channel = data->pwm_cfg[attr->index] >> ADT7462_PWM_CHANNEL_SHIFT;
+
+	switch (channel) {
+	case 0: /* temp[1234] only */
+	case 1:
+	case 2:
+	case 3:
+		return sprintf(buf, "%d\n", (1 << channel));
+	case 5: /* temp1 & temp4  */
+		return sprintf(buf, "9\n");
+	case 6:
+		return sprintf(buf, "15\n");
+	default:
+		return sprintf(buf, "0\n");
+	}
+}
+
+static int cvt_auto_temp(int input)
+{
+	if (input == 0xF)
+		return 6;
+	if (input == 0x9)
+		return 5;
+	if (input < 1 || !is_power_of_2(input))
+		return -EINVAL;
+	return ilog2(input);
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+				 struct device_attribute *devattr,
+				 const char *buf,
+				 size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7462_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = cvt_auto_temp(temp);
+	if (temp < 0)
+		return temp;
+
+	set_pwm_channel(client, data, attr->index, temp);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM1 | ADT7462_LT_ALARM);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM1 | ADT7462_R1T_ALARM);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM1 | ADT7462_R2T_ALARM);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM1 | ADT7462_R3T_ALARM);
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO, show_volt_max,
+		    set_volt_max, 12);
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO, show_volt_min,
+		    set_volt_min, 12);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_voltage, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_voltage, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_voltage, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_voltage, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_voltage, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_voltage, NULL, 12);
+
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_voltage_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_voltage_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_voltage_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_voltage_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_voltage_label, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_voltage_label, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_voltage_label, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_voltage_label, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_voltage_label, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_voltage_label, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_voltage_label, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_voltage_label, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_label, S_IRUGO, show_voltage_label, NULL, 12);
+
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V0_ALARM);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V7_ALARM);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V2_ALARM);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V6_ALARM);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V5_ALARM);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V4_ALARM);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V3_ALARM);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM2 | ADT7462_V1_ALARM);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM3 | ADT7462_V10_ALARM);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM3 | ADT7462_V9_ALARM);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM3 | ADT7462_V8_ALARM);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM3 | ADT7462_V11_ALARM);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM3 | ADT7462_V12_ALARM);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F0_ALARM);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F1_ALARM);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F2_ALARM);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F3_ALARM);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F4_ALARM);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F5_ALARM);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F6_ALARM);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7462_ALARM4 | ADT7462_F7_ALARM);
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+		    show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point1_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point1_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point2_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point2_hyst, S_IWUSR | S_IRUGO,
+		    show_pwm_hyst, set_pwm_hyst, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmax, set_pwm_tmax, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmax, set_pwm_tmax, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point2_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmax, set_pwm_tmax, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point2_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmax, set_pwm_tmax, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7462_attrs[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp3_label.dev_attr.attr,
+	&sensor_dev_attr_temp4_label.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_alarm.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,
+	&sensor_dev_attr_in12_max.dev_attr.attr,
+	&sensor_dev_attr_in13_max.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,
+	&sensor_dev_attr_in12_min.dev_attr.attr,
+	&sensor_dev_attr_in13_min.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	&sensor_dev_attr_in5_label.dev_attr.attr,
+	&sensor_dev_attr_in6_label.dev_attr.attr,
+	&sensor_dev_attr_in7_label.dev_attr.attr,
+	&sensor_dev_attr_in8_label.dev_attr.attr,
+	&sensor_dev_attr_in9_label.dev_attr.attr,
+	&sensor_dev_attr_in10_label.dev_attr.attr,
+	&sensor_dev_attr_in11_label.dev_attr.attr,
+	&sensor_dev_attr_in12_label.dev_attr.attr,
+	&sensor_dev_attr_in13_label.dev_attr.attr,
+
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	&sensor_dev_attr_in8_alarm.dev_attr.attr,
+	&sensor_dev_attr_in9_alarm.dev_attr.attr,
+	&sensor_dev_attr_in10_alarm.dev_attr.attr,
+	&sensor_dev_attr_in11_alarm.dev_attr.attr,
+	&sensor_dev_attr_in12_alarm.dev_attr.attr,
+	&sensor_dev_attr_in13_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan5_min.dev_attr.attr,
+	&sensor_dev_attr_fan6_min.dev_attr.attr,
+	&sensor_dev_attr_fan7_min.dev_attr.attr,
+	&sensor_dev_attr_fan8_min.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+	&sensor_dev_attr_fan7_input.dev_attr.attr,
+	&sensor_dev_attr_fan8_input.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan7_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan8_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_force_pwm_max.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_auto_point1_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point1_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_auto_point1_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_auto_point2_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point2_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_auto_point2_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp4_auto_point1_temp.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp4_auto_point2_temp.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(adt7462);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adt7462_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int vendor, device, revision;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	vendor = i2c_smbus_read_byte_data(client, ADT7462_REG_VENDOR);
+	if (vendor != ADT7462_VENDOR)
+		return -ENODEV;
+
+	device = i2c_smbus_read_byte_data(client, ADT7462_REG_DEVICE);
+	if (device != ADT7462_DEVICE)
+		return -ENODEV;
+
+	revision = i2c_smbus_read_byte_data(client, ADT7462_REG_REVISION);
+	if (revision != ADT7462_REVISION)
+		return -ENODEV;
+
+	strlcpy(info->type, "adt7462", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int adt7462_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct adt7462_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct adt7462_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->lock);
+
+	dev_info(&client->dev, "%s chip found\n", client->name);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   adt7462_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id adt7462_id[] = {
+	{ "adt7462", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7462_id);
+
+static struct i2c_driver adt7462_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7462",
+	},
+	.probe		= adt7462_probe,
+	.id_table	= adt7462_id,
+	.detect		= adt7462_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adt7462_driver);
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("ADT7462 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
new file mode 100644
index 0000000..f5da39a
--- /dev/null
+++ b/drivers/hwmon/adt7470.c
@@ -0,0 +1,1300 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7470
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.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/delay.h>
+#include <linux/log2.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
+
+/* ADT7470 registers */
+#define ADT7470_REG_BASE_ADDR			0x20
+#define ADT7470_REG_TEMP_BASE_ADDR		0x20
+#define ADT7470_REG_TEMP_MAX_ADDR		0x29
+#define ADT7470_REG_FAN_BASE_ADDR		0x2A
+#define ADT7470_REG_FAN_MAX_ADDR		0x31
+#define ADT7470_REG_PWM_BASE_ADDR		0x32
+#define ADT7470_REG_PWM_MAX_ADDR		0x35
+#define ADT7470_REG_PWM_MAX_BASE_ADDR		0x38
+#define ADT7470_REG_PWM_MAX_MAX_ADDR		0x3B
+#define ADT7470_REG_CFG				0x40
+#define		ADT7470_FSPD_MASK		0x04
+#define ADT7470_REG_ALARM1			0x41
+#define		ADT7470_R1T_ALARM		0x01
+#define		ADT7470_R2T_ALARM		0x02
+#define		ADT7470_R3T_ALARM		0x04
+#define		ADT7470_R4T_ALARM		0x08
+#define		ADT7470_R5T_ALARM		0x10
+#define		ADT7470_R6T_ALARM		0x20
+#define		ADT7470_R7T_ALARM		0x40
+#define		ADT7470_OOL_ALARM		0x80
+#define ADT7470_REG_ALARM2			0x42
+#define		ADT7470_R8T_ALARM		0x01
+#define		ADT7470_R9T_ALARM		0x02
+#define		ADT7470_R10T_ALARM		0x04
+#define		ADT7470_FAN1_ALARM		0x10
+#define		ADT7470_FAN2_ALARM		0x20
+#define		ADT7470_FAN3_ALARM		0x40
+#define		ADT7470_FAN4_ALARM		0x80
+#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR	0x44
+#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR	0x57
+#define ADT7470_REG_FAN_MIN_BASE_ADDR		0x58
+#define ADT7470_REG_FAN_MIN_MAX_ADDR		0x5F
+#define ADT7470_REG_FAN_MAX_BASE_ADDR		0x60
+#define ADT7470_REG_FAN_MAX_MAX_ADDR		0x67
+#define ADT7470_REG_PWM_CFG_BASE_ADDR		0x68
+#define ADT7470_REG_PWM12_CFG			0x68
+#define		ADT7470_PWM2_AUTO_MASK		0x40
+#define		ADT7470_PWM1_AUTO_MASK		0x80
+#define		ADT7470_PWM_AUTO_MASK		0xC0
+#define ADT7470_REG_PWM34_CFG			0x69
+#define		ADT7470_PWM3_AUTO_MASK		0x40
+#define		ADT7470_PWM4_AUTO_MASK		0x80
+#define	ADT7470_REG_PWM_MIN_BASE_ADDR		0x6A
+#define ADT7470_REG_PWM_MIN_MAX_ADDR		0x6D
+#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR	0x6E
+#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR	0x71
+#define ADT7470_REG_ACOUSTICS12			0x75
+#define ADT7470_REG_ACOUSTICS34			0x76
+#define ADT7470_REG_DEVICE			0x3D
+#define ADT7470_REG_VENDOR			0x3E
+#define ADT7470_REG_REVISION			0x3F
+#define ADT7470_REG_ALARM1_MASK			0x72
+#define ADT7470_REG_ALARM2_MASK			0x73
+#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR	0x7C
+#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR	0x7D
+#define ADT7470_REG_MAX_ADDR			0x81
+
+#define ADT7470_TEMP_COUNT	10
+#define ADT7470_TEMP_REG(x)	(ADT7470_REG_TEMP_BASE_ADDR + (x))
+#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
+#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
+				((x) * 2) + 1)
+
+#define ADT7470_FAN_COUNT	4
+#define ADT7470_REG_FAN(x)	(ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MIN(x)	(ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MAX(x)	(ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
+
+#define ADT7470_PWM_COUNT	4
+#define ADT7470_REG_PWM(x)	(ADT7470_REG_PWM_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MAX(x)	(ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MIN(x)	(ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_TMIN(x)	(ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_CFG(x)	(ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
+#define ADT7470_REG_PWM_AUTO_TEMP(x)	(ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
+					((x) / 2))
+
+#define ALARM2(x)		((x) << 8)
+
+#define ADT7470_VENDOR		0x41
+#define ADT7470_DEVICE		0x70
+/* datasheet only mentions a revision 2 */
+#define ADT7470_REVISION	0x02
+
+/* "all temps" according to hwmon sysfs interface spec */
+#define ADT7470_PWM_ALL_TEMPS	0x3FF
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL	(5 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL	(60 * HZ)
+
+/* Wait at least 200ms per sensor for 10 sensors */
+#define TEMP_COLLECTION_TIME	2000
+
+/* auto update thing won't fire more than every 2s */
+#define AUTO_UPDATE_INTERVAL	2000
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID	65535
+#define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
+
+struct adt7470_data {
+	struct i2c_client	*client;
+	struct mutex		lock;
+	char			sensors_valid;
+	char			limits_valid;
+	unsigned long		sensors_last_updated;	/* In jiffies */
+	unsigned long		limits_last_updated;	/* In jiffies */
+
+	int			num_temp_sensors;	/* -1 = probe */
+	int			temperatures_probed;
+
+	s8			temp[ADT7470_TEMP_COUNT];
+	s8			temp_min[ADT7470_TEMP_COUNT];
+	s8			temp_max[ADT7470_TEMP_COUNT];
+	u16			fan[ADT7470_FAN_COUNT];
+	u16			fan_min[ADT7470_FAN_COUNT];
+	u16			fan_max[ADT7470_FAN_COUNT];
+	u16			alarm;
+	u16			alarms_mask;
+	u8			force_pwm_max;
+	u8			pwm[ADT7470_PWM_COUNT];
+	u8			pwm_max[ADT7470_PWM_COUNT];
+	u8			pwm_automatic[ADT7470_PWM_COUNT];
+	u8			pwm_min[ADT7470_PWM_COUNT];
+	s8			pwm_tmin[ADT7470_PWM_COUNT];
+	u8			pwm_auto_temp[ADT7470_PWM_COUNT];
+
+	struct task_struct	*auto_update;
+	struct completion	auto_update_stop;
+	unsigned int		auto_update_interval;
+};
+
+/*
+ * 16-bit registers on the ADT7470 are low-byte first.  The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg)
+{
+	u16 foo;
+	foo = i2c_smbus_read_byte_data(client, reg);
+	foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+	return foo;
+}
+
+static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
+					  u16 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
+	       || i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+}
+
+/* Probe for temperature sensors.  Assumes lock is held */
+static int adt7470_read_temperatures(struct i2c_client *client,
+				     struct adt7470_data *data)
+{
+	unsigned long res;
+	int i;
+	u8 cfg, pwm[4], pwm_cfg[2];
+
+	/* save pwm[1-4] config register */
+	pwm_cfg[0] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(0));
+	pwm_cfg[1] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(2));
+
+	/* set manual pwm to whatever it is set to now */
+	for (i = 0; i < ADT7470_FAN_COUNT; i++)
+		pwm[i] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM(i));
+
+	/* put pwm in manual mode */
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0),
+		pwm_cfg[0] & ~(ADT7470_PWM_AUTO_MASK));
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2),
+		pwm_cfg[1] & ~(ADT7470_PWM_AUTO_MASK));
+
+	/* write pwm control to whatever it was */
+	for (i = 0; i < ADT7470_FAN_COUNT; i++)
+		i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(i), pwm[i]);
+
+	/* start reading temperature sensors */
+	cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+	cfg |= 0x80;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+	/* Delay is 200ms * number of temp sensors. */
+	res = msleep_interruptible((data->num_temp_sensors >= 0 ?
+				    data->num_temp_sensors * 200 :
+				    TEMP_COLLECTION_TIME));
+
+	/* done reading temperature sensors */
+	cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+	cfg &= ~0x80;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+	/* restore pwm[1-4] config registers */
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+
+	if (res) {
+		pr_err("ha ha, interrupted\n");
+		return -EAGAIN;
+	}
+
+	/* Only count fans if we have to */
+	if (data->num_temp_sensors >= 0)
+		return 0;
+
+	for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
+		data->temp[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_TEMP_REG(i));
+		if (data->temp[i])
+			data->num_temp_sensors = i + 1;
+	}
+	data->temperatures_probed = 1;
+	return 0;
+}
+
+static int adt7470_update_thread(void *p)
+{
+	struct i2c_client *client = p;
+	struct adt7470_data *data = i2c_get_clientdata(client);
+
+	while (!kthread_should_stop()) {
+		mutex_lock(&data->lock);
+		adt7470_read_temperatures(client, data);
+		mutex_unlock(&data->lock);
+		if (kthread_should_stop())
+			break;
+		msleep_interruptible(data->auto_update_interval);
+	}
+
+	complete_all(&data->auto_update_stop);
+	return 0;
+}
+
+static struct adt7470_data *adt7470_update_device(struct device *dev)
+{
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long local_jiffies = jiffies;
+	u8 cfg;
+	int i;
+	int need_sensors = 1;
+	int need_limits = 1;
+
+	/*
+	 * Figure out if we need to update the shadow registers.
+	 * Lockless means that we may occasionally report out of
+	 * date data.
+	 */
+	if (time_before(local_jiffies, data->sensors_last_updated +
+			SENSOR_REFRESH_INTERVAL) &&
+	    data->sensors_valid)
+		need_sensors = 0;
+
+	if (time_before(local_jiffies, data->limits_last_updated +
+			LIMIT_REFRESH_INTERVAL) &&
+	    data->limits_valid)
+		need_limits = 0;
+
+	if (!need_sensors && !need_limits)
+		return data;
+
+	mutex_lock(&data->lock);
+	if (!need_sensors)
+		goto no_sensor_update;
+
+	if (!data->temperatures_probed)
+		adt7470_read_temperatures(client, data);
+	else
+		for (i = 0; i < ADT7470_TEMP_COUNT; i++)
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_TEMP_REG(i));
+
+	for (i = 0; i < ADT7470_FAN_COUNT; i++)
+		data->fan[i] = adt7470_read_word_data(client,
+						ADT7470_REG_FAN(i));
+
+	for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+		int reg;
+		int reg_mask;
+
+		data->pwm[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_REG_PWM(i));
+
+		if (i % 2)
+			reg_mask = ADT7470_PWM2_AUTO_MASK;
+		else
+			reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+		reg = ADT7470_REG_PWM_CFG(i);
+		if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
+			data->pwm_automatic[i] = 1;
+		else
+			data->pwm_automatic[i] = 0;
+
+		reg = ADT7470_REG_PWM_AUTO_TEMP(i);
+		cfg = i2c_smbus_read_byte_data(client, reg);
+		if (!(i % 2))
+			data->pwm_auto_temp[i] = cfg >> 4;
+		else
+			data->pwm_auto_temp[i] = cfg & 0xF;
+	}
+
+	if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) &
+	    ADT7470_FSPD_MASK)
+		data->force_pwm_max = 1;
+	else
+		data->force_pwm_max = 0;
+
+	data->alarm = i2c_smbus_read_byte_data(client, ADT7470_REG_ALARM1);
+	if (data->alarm & ADT7470_OOL_ALARM)
+		data->alarm |= ALARM2(i2c_smbus_read_byte_data(client,
+							ADT7470_REG_ALARM2));
+	data->alarms_mask = adt7470_read_word_data(client,
+						   ADT7470_REG_ALARM1_MASK);
+
+	data->sensors_last_updated = local_jiffies;
+	data->sensors_valid = 1;
+
+no_sensor_update:
+	if (!need_limits)
+		goto out;
+
+	for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
+		data->temp_min[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_TEMP_MIN_REG(i));
+		data->temp_max[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_TEMP_MAX_REG(i));
+	}
+
+	for (i = 0; i < ADT7470_FAN_COUNT; i++) {
+		data->fan_min[i] = adt7470_read_word_data(client,
+						ADT7470_REG_FAN_MIN(i));
+		data->fan_max[i] = adt7470_read_word_data(client,
+						ADT7470_REG_FAN_MAX(i));
+	}
+
+	for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+		data->pwm_max[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_REG_PWM_MAX(i));
+		data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_REG_PWM_MIN(i));
+		data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+						ADT7470_REG_PWM_TMIN(i));
+	}
+
+	data->limits_last_updated = local_jiffies;
+	data->limits_valid = 1;
+
+out:
+	mutex_unlock(&data->lock);
+	return data;
+}
+
+static ssize_t show_auto_update_interval(struct device *dev,
+					 struct device_attribute *devattr,
+					 char *buf)
+{
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->auto_update_interval);
+}
+
+static ssize_t set_auto_update_interval(struct device *dev,
+					struct device_attribute *devattr,
+					const char *buf,
+					size_t count)
+{
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 60000);
+
+	mutex_lock(&data->lock);
+	data->auto_update_interval = temp;
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_num_temp_sensors(struct device *dev,
+				     struct device_attribute *devattr,
+				     char *buf)
+{
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->num_temp_sensors);
+}
+
+static ssize_t set_num_temp_sensors(struct device *dev,
+				    struct device_attribute *devattr,
+				    const char *buf,
+				    size_t count)
+{
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, -1, 10);
+
+	mutex_lock(&data->lock);
+	data->num_temp_sensors = temp;
+	if (temp < 0)
+		data->temperatures_probed = 0;
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
+}
+
+static ssize_t set_temp_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+	temp = clamp_val(temp, -128, 127);
+
+	mutex_lock(&data->lock);
+	data->temp_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+	temp = clamp_val(temp, -128, 127);
+
+	mutex_lock(&data->lock);
+	data->temp_max[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+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 adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
+}
+
+static ssize_t show_alarm_mask(struct device *dev,
+			   struct device_attribute *devattr,
+			   char *buf)
+{
+	struct adt7470_data *data = adt7470_update_device(dev);
+
+	return sprintf(buf, "%x\n", data->alarms_mask);
+}
+
+static ssize_t show_fan_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+
+	if (FAN_DATA_VALID(data->fan_max[attr->index]))
+		return sprintf(buf, "%d\n",
+			       FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_max(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !temp)
+		return -EINVAL;
+
+	temp = FAN_RPM_TO_PERIOD(temp);
+	temp = clamp_val(temp, 1, 65534);
+
+	mutex_lock(&data->lock);
+	data->fan_max[attr->index] = temp;
+	adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+
+	if (FAN_DATA_VALID(data->fan_min[attr->index]))
+		return sprintf(buf, "%d\n",
+			       FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_min(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp) || !temp)
+		return -EINVAL;
+
+	temp = FAN_RPM_TO_PERIOD(temp);
+	temp = clamp_val(temp, 1, 65534);
+
+	mutex_lock(&data->lock);
+	data->fan_min[attr->index] = temp;
+	adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+
+	if (FAN_DATA_VALID(data->fan[attr->index]))
+		return sprintf(buf, "%d\n",
+			       FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->force_pwm_max);
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+				 struct device_attribute *devattr,
+				 const char *buf,
+				 size_t count)
+{
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	u8 reg;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	data->force_pwm_max = temp;
+	reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+	if (temp)
+		reg |= ADT7470_FSPD_MASK;
+	else
+		reg &= ~ADT7470_FSPD_MASK;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf,
+			   size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm_max[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+			   struct device_attribute *devattr,
+			   const char *buf,
+			   size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 255);
+
+	mutex_lock(&data->lock);
+	data->pwm_min[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	/* the datasheet says that tmax = tmin + 20C */
+	return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = DIV_ROUND_CLOSEST(temp, 1000);
+	temp = clamp_val(temp, -128, 127);
+
+	mutex_lock(&data->lock);
+	data->pwm_tmin[attr->index] = temp;
+	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index),
+				  temp);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf,
+			    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
+	int pwm_auto_reg_mask;
+	long temp;
+	u8 reg;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	if (attr->index % 2)
+		pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
+	else
+		pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+	if (temp != 2 && temp != 1)
+		return -EINVAL;
+	temp--;
+
+	mutex_lock(&data->lock);
+	data->pwm_automatic[attr->index] = temp;
+	reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+	if (temp)
+		reg |= pwm_auto_reg_mask;
+	else
+		reg &= ~pwm_auto_reg_mask;
+	i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+	u8 ctrl = data->pwm_auto_temp[attr->index];
+
+	if (ctrl)
+		return sprintf(buf, "%d\n", 1 << (ctrl - 1));
+	else
+		return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
+}
+
+static int cvt_auto_temp(int input)
+{
+	if (input == ADT7470_PWM_ALL_TEMPS)
+		return 0;
+	if (input < 1 || !is_power_of_2(input))
+		return -EINVAL;
+	return ilog2(input) + 1;
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+				 struct device_attribute *devattr,
+				 const char *buf,
+				 size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+	long temp;
+	u8 reg;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = cvt_auto_temp(temp);
+	if (temp < 0)
+		return temp;
+
+	mutex_lock(&data->lock);
+	data->pwm_automatic[attr->index] = temp;
+	reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+
+	if (!(attr->index % 2)) {
+		reg &= 0xF;
+		reg |= (temp << 4) & 0xF0;
+	} else {
+		reg &= 0xF0;
+		reg |= temp & 0xF;
+	}
+
+	i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct adt7470_data *data = adt7470_update_device(dev);
+
+	if (data->alarm & attr->index)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL);
+static DEVICE_ATTR(num_temp_sensors, S_IWUSR | S_IRUGO, show_num_temp_sensors,
+		   set_num_temp_sensors);
+static DEVICE_ATTR(auto_update_interval, S_IWUSR | S_IRUGO,
+		   show_auto_update_interval, set_auto_update_interval);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 7);
+static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 8);
+static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max,
+		    set_temp_max, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 4);
+static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 5);
+static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 6);
+static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 7);
+static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 8);
+static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min,
+		    set_temp_min, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R1T_ALARM);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R2T_ALARM);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R3T_ALARM);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R4T_ALARM);
+static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R5T_ALARM);
+static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R6T_ALARM);
+static SENSOR_DEVICE_ATTR(temp7_alarm, S_IRUGO, show_alarm, NULL,
+			  ADT7470_R7T_ALARM);
+static SENSOR_DEVICE_ATTR(temp8_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_R8T_ALARM));
+static SENSOR_DEVICE_ATTR(temp9_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_R9T_ALARM));
+static SENSOR_DEVICE_ATTR(temp10_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_R10T_ALARM));
+
+static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
+		    set_fan_max, 0);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
+		    set_fan_max, 1);
+static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
+		    set_fan_max, 2);
+static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max,
+		    set_fan_max, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    set_fan_min, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_FAN1_ALARM));
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_FAN2_ALARM));
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_FAN3_ALARM));
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
+			  ALARM2(ADT7470_FAN4_ALARM));
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+		    show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+		    show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+		    NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+		    NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+		    NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+		    NULL, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+		    set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+		    show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7470_attrs[] = {
+	&dev_attr_alarm_mask.attr,
+	&dev_attr_num_temp_sensors.attr,
+	&dev_attr_auto_update_interval.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp6_max.dev_attr.attr,
+	&sensor_dev_attr_temp7_max.dev_attr.attr,
+	&sensor_dev_attr_temp8_max.dev_attr.attr,
+	&sensor_dev_attr_temp9_max.dev_attr.attr,
+	&sensor_dev_attr_temp10_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp5_min.dev_attr.attr,
+	&sensor_dev_attr_temp6_min.dev_attr.attr,
+	&sensor_dev_attr_temp7_min.dev_attr.attr,
+	&sensor_dev_attr_temp8_min.dev_attr.attr,
+	&sensor_dev_attr_temp9_min.dev_attr.attr,
+	&sensor_dev_attr_temp10_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp9_input.dev_attr.attr,
+	&sensor_dev_attr_temp10_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp9_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp10_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_max.dev_attr.attr,
+	&sensor_dev_attr_fan2_max.dev_attr.attr,
+	&sensor_dev_attr_fan3_max.dev_attr.attr,
+	&sensor_dev_attr_fan4_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	&sensor_dev_attr_force_pwm_max.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(adt7470);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adt7470_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int vendor, device, revision;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
+	if (vendor != ADT7470_VENDOR)
+		return -ENODEV;
+
+	device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
+	if (device != ADT7470_DEVICE)
+		return -ENODEV;
+
+	revision = i2c_smbus_read_byte_data(client, ADT7470_REG_REVISION);
+	if (revision != ADT7470_REVISION)
+		return -ENODEV;
+
+	strlcpy(info->type, "adt7470", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adt7470_init_client(struct i2c_client *client)
+{
+	int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+
+	if (reg < 0) {
+		dev_err(&client->dev, "cannot read configuration register\n");
+	} else {
+		/* start monitoring (and do a self-test) */
+		i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
+	}
+}
+
+static int adt7470_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct adt7470_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->num_temp_sensors = -1;
+	data->auto_update_interval = AUTO_UPDATE_INTERVAL;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->lock);
+
+	dev_info(&client->dev, "%s chip found\n", client->name);
+
+	/* Initialize the ADT7470 chip */
+	adt7470_init_client(client);
+
+	/* Register sysfs hooks */
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   adt7470_groups);
+
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	init_completion(&data->auto_update_stop);
+	data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
+					dev_name(hwmon_dev));
+	if (IS_ERR(data->auto_update)) {
+		return PTR_ERR(data->auto_update);
+	}
+
+	return 0;
+}
+
+static int adt7470_remove(struct i2c_client *client)
+{
+	struct adt7470_data *data = i2c_get_clientdata(client);
+
+	kthread_stop(data->auto_update);
+	wait_for_completion(&data->auto_update_stop);
+	return 0;
+}
+
+static const struct i2c_device_id adt7470_id[] = {
+	{ "adt7470", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7470_id);
+
+static struct i2c_driver adt7470_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7470",
+	},
+	.probe		= adt7470_probe,
+	.remove		= adt7470_remove,
+	.id_table	= adt7470_id,
+	.detect		= adt7470_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adt7470_driver);
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("ADT7470 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
new file mode 100644
index 0000000..3cefd1a
--- /dev/null
+++ b/drivers/hwmon/adt7475.c
@@ -0,0 +1,1631 @@
+/*
+ * adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives
+ * Copyright (C) 2007-2008, Advanced Micro Devices, Inc.
+ * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
+ * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2009 Jean Delvare <jdelvare@suse.de>
+ *
+ * Derived from the lm83 driver by Jean Delvare
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/jiffies.h>
+
+/* Indexes for the sysfs hooks */
+
+#define INPUT		0
+#define MIN		1
+#define MAX		2
+#define CONTROL		3
+#define OFFSET		3
+#define AUTOMIN		4
+#define THERM		5
+#define HYSTERSIS	6
+
+/*
+ * These are unique identifiers for the sysfs functions - unlike the
+ * numbers above, these are not also indexes into an array
+ */
+
+#define ALARM		9
+#define FAULT		10
+
+/* 7475 Common Registers */
+
+#define REG_DEVREV2		0x12	/* ADT7490 only */
+
+#define REG_VTT			0x1E	/* ADT7490 only */
+#define REG_EXTEND3		0x1F	/* ADT7490 only */
+
+#define REG_VOLTAGE_BASE	0x20
+#define REG_TEMP_BASE		0x25
+#define REG_TACH_BASE		0x28
+#define REG_PWM_BASE		0x30
+#define REG_PWM_MAX_BASE	0x38
+
+#define REG_DEVID		0x3D
+#define REG_VENDID		0x3E
+#define REG_DEVID2		0x3F
+
+#define REG_STATUS1		0x41
+#define REG_STATUS2		0x42
+
+#define REG_VID			0x43	/* ADT7476 only */
+
+#define REG_VOLTAGE_MIN_BASE	0x44
+#define REG_VOLTAGE_MAX_BASE	0x45
+
+#define REG_TEMP_MIN_BASE	0x4E
+#define REG_TEMP_MAX_BASE	0x4F
+
+#define REG_TACH_MIN_BASE	0x54
+
+#define REG_PWM_CONFIG_BASE	0x5C
+
+#define REG_TEMP_TRANGE_BASE	0x5F
+
+#define REG_PWM_MIN_BASE	0x64
+
+#define REG_TEMP_TMIN_BASE	0x67
+#define REG_TEMP_THERM_BASE	0x6A
+
+#define REG_REMOTE1_HYSTERSIS	0x6D
+#define REG_REMOTE2_HYSTERSIS	0x6E
+
+#define REG_TEMP_OFFSET_BASE	0x70
+
+#define REG_CONFIG2		0x73
+
+#define REG_EXTEND1		0x76
+#define REG_EXTEND2		0x77
+
+#define REG_CONFIG3		0x78
+#define REG_CONFIG5		0x7C
+#define REG_CONFIG4		0x7D
+
+#define REG_STATUS4		0x81	/* ADT7490 only */
+
+#define REG_VTT_MIN		0x84	/* ADT7490 only */
+#define REG_VTT_MAX		0x86	/* ADT7490 only */
+
+#define VID_VIDSEL		0x80	/* ADT7476 only */
+
+#define CONFIG2_ATTN		0x20
+
+#define CONFIG3_SMBALERT	0x01
+#define CONFIG3_THERM		0x02
+
+#define CONFIG4_PINFUNC		0x03
+#define CONFIG4_MAXDUTY		0x08
+#define CONFIG4_ATTN_IN10	0x30
+#define CONFIG4_ATTN_IN43	0xC0
+
+#define CONFIG5_TWOSCOMP	0x01
+#define CONFIG5_TEMPOFFSET	0x02
+#define CONFIG5_VIDGPIO		0x10	/* ADT7476 only */
+
+/* ADT7475 Settings */
+
+#define ADT7475_VOLTAGE_COUNT	5	/* Not counting Vtt */
+#define ADT7475_TEMP_COUNT	3
+#define ADT7475_TACH_COUNT	4
+#define ADT7475_PWM_COUNT	3
+
+/* Macro to read the registers */
+
+#define adt7475_read(reg) i2c_smbus_read_byte_data(client, (reg))
+
+/* Macros to easily index the registers */
+
+#define TACH_REG(idx) (REG_TACH_BASE + ((idx) * 2))
+#define TACH_MIN_REG(idx) (REG_TACH_MIN_BASE + ((idx) * 2))
+
+#define PWM_REG(idx) (REG_PWM_BASE + (idx))
+#define PWM_MAX_REG(idx) (REG_PWM_MAX_BASE + (idx))
+#define PWM_MIN_REG(idx) (REG_PWM_MIN_BASE + (idx))
+#define PWM_CONFIG_REG(idx) (REG_PWM_CONFIG_BASE + (idx))
+
+#define VOLTAGE_REG(idx) (REG_VOLTAGE_BASE + (idx))
+#define VOLTAGE_MIN_REG(idx) (REG_VOLTAGE_MIN_BASE + ((idx) * 2))
+#define VOLTAGE_MAX_REG(idx) (REG_VOLTAGE_MAX_BASE + ((idx) * 2))
+
+#define TEMP_REG(idx) (REG_TEMP_BASE + (idx))
+#define TEMP_MIN_REG(idx) (REG_TEMP_MIN_BASE + ((idx) * 2))
+#define TEMP_MAX_REG(idx) (REG_TEMP_MAX_BASE + ((idx) * 2))
+#define TEMP_TMIN_REG(idx) (REG_TEMP_TMIN_BASE + (idx))
+#define TEMP_THERM_REG(idx) (REG_TEMP_THERM_BASE + (idx))
+#define TEMP_OFFSET_REG(idx) (REG_TEMP_OFFSET_BASE + (idx))
+#define TEMP_TRANGE_REG(idx) (REG_TEMP_TRANGE_BASE + (idx))
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips { adt7473, adt7475, adt7476, adt7490 };
+
+static const struct i2c_device_id adt7475_id[] = {
+	{ "adt7473", adt7473 },
+	{ "adt7475", adt7475 },
+	{ "adt7476", adt7476 },
+	{ "adt7490", adt7490 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7475_id);
+
+struct adt7475_data {
+	struct device *hwmon_dev;
+	struct mutex lock;
+
+	unsigned long measure_updated;
+	unsigned long limits_updated;
+	char valid;
+
+	u8 config4;
+	u8 config5;
+	u8 has_voltage;
+	u8 bypass_attn;		/* Bypass voltage attenuator */
+	u8 has_pwm2:1;
+	u8 has_fan4:1;
+	u8 has_vid:1;
+	u32 alarms;
+	u16 voltage[3][6];
+	u16 temp[7][3];
+	u16 tach[2][4];
+	u8 pwm[4][3];
+	u8 range[3];
+	u8 pwmctl[3];
+	u8 pwmchan[3];
+
+	u8 vid;
+	u8 vrm;
+};
+
+static struct i2c_driver adt7475_driver;
+static struct adt7475_data *adt7475_update_device(struct device *dev);
+static void adt7475_read_hystersis(struct i2c_client *client);
+static void adt7475_read_pwm(struct i2c_client *client, int index);
+
+/* Given a temp value, convert it to register value */
+
+static inline u16 temp2reg(struct adt7475_data *data, long val)
+{
+	u16 ret;
+
+	if (!(data->config5 & CONFIG5_TWOSCOMP)) {
+		val = clamp_val(val, -64000, 191000);
+		ret = (val + 64500) / 1000;
+	} else {
+		val = clamp_val(val, -128000, 127000);
+		if (val < -500)
+			ret = (256500 + val) / 1000;
+		else
+			ret = (val + 500) / 1000;
+	}
+
+	return ret << 2;
+}
+
+/* Given a register value, convert it to a real temp value */
+
+static inline int reg2temp(struct adt7475_data *data, u16 reg)
+{
+	if (data->config5 & CONFIG5_TWOSCOMP) {
+		if (reg >= 512)
+			return (reg - 1024) * 250;
+		else
+			return reg * 250;
+	} else
+		return (reg - 256) * 250;
+}
+
+static inline int tach2rpm(u16 tach)
+{
+	if (tach == 0 || tach == 0xFFFF)
+		return 0;
+
+	return (90000 * 60) / tach;
+}
+
+static inline u16 rpm2tach(unsigned long rpm)
+{
+	if (rpm == 0)
+		return 0;
+
+	return clamp_val((90000 * 60) / rpm, 1, 0xFFFF);
+}
+
+/* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
+static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 1][2] = {
+	{ 45, 94 },	/* +2.5V */
+	{ 175, 525 },	/* Vccp */
+	{ 68, 71 },	/* Vcc */
+	{ 93, 47 },	/* +5V */
+	{ 120, 20 },	/* +12V */
+	{ 45, 45 },	/* Vtt */
+};
+
+static inline int reg2volt(int channel, u16 reg, u8 bypass_attn)
+{
+	const int *r = adt7473_in_scaling[channel];
+
+	if (bypass_attn & (1 << channel))
+		return DIV_ROUND_CLOSEST(reg * 2250, 1024);
+	return DIV_ROUND_CLOSEST(reg * (r[0] + r[1]) * 2250, r[1] * 1024);
+}
+
+static inline u16 volt2reg(int channel, long volt, u8 bypass_attn)
+{
+	const int *r = adt7473_in_scaling[channel];
+	long reg;
+
+	if (bypass_attn & (1 << channel))
+		reg = (volt * 1024) / 2250;
+	else
+		reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250);
+	return clamp_val(reg, 0, 1023) & (0xff << 2);
+}
+
+static u16 adt7475_read_word(struct i2c_client *client, int reg)
+{
+	u16 val;
+
+	val = i2c_smbus_read_byte_data(client, reg);
+	val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8);
+
+	return val;
+}
+
+static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
+{
+	i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+	i2c_smbus_write_byte_data(client, reg, val & 0xFF);
+}
+
+/*
+ * Find the nearest value in a table - used for pwm frequency and
+ * auto temp range
+ */
+static int find_nearest(long val, const int *array, int size)
+{
+	int i;
+
+	if (val < array[0])
+		return 0;
+
+	if (val > array[size - 1])
+		return size - 1;
+
+	for (i = 0; i < size - 1; i++) {
+		int a, b;
+
+		if (val > array[i + 1])
+			continue;
+
+		a = val - array[i];
+		b = array[i + 1] - val;
+
+		return (a <= b) ? i : i + 1;
+	}
+
+	return 0;
+}
+
+static ssize_t show_voltage(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	unsigned short val;
+
+	switch (sattr->nr) {
+	case ALARM:
+		return sprintf(buf, "%d\n",
+			       (data->alarms >> sattr->index) & 1);
+	default:
+		val = data->voltage[sattr->nr][sattr->index];
+		return sprintf(buf, "%d\n",
+			       reg2volt(sattr->index, val, data->bypass_attn));
+	}
+}
+
+static ssize_t set_voltage(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	unsigned char reg;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+
+	data->voltage[sattr->nr][sattr->index] =
+				volt2reg(sattr->index, val, data->bypass_attn);
+
+	if (sattr->index < ADT7475_VOLTAGE_COUNT) {
+		if (sattr->nr == MIN)
+			reg = VOLTAGE_MIN_REG(sattr->index);
+		else
+			reg = VOLTAGE_MAX_REG(sattr->index);
+	} else {
+		if (sattr->nr == MIN)
+			reg = REG_VTT_MIN;
+		else
+			reg = REG_VTT_MAX;
+	}
+
+	i2c_smbus_write_byte_data(client, reg,
+				  data->voltage[sattr->nr][sattr->index] >> 2);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int out;
+
+	switch (sattr->nr) {
+	case HYSTERSIS:
+		mutex_lock(&data->lock);
+		out = data->temp[sattr->nr][sattr->index];
+		if (sattr->index != 1)
+			out = (out >> 4) & 0xF;
+		else
+			out = (out & 0xF);
+		/*
+		 * Show the value as an absolute number tied to
+		 * THERM
+		 */
+		out = reg2temp(data, data->temp[THERM][sattr->index]) -
+			out * 1000;
+		mutex_unlock(&data->lock);
+		break;
+
+	case OFFSET:
+		/*
+		 * Offset is always 2's complement, regardless of the
+		 * setting in CONFIG5
+		 */
+		mutex_lock(&data->lock);
+		out = (s8)data->temp[sattr->nr][sattr->index];
+		if (data->config5 & CONFIG5_TEMPOFFSET)
+			out *= 1000;
+		else
+			out *= 500;
+		mutex_unlock(&data->lock);
+		break;
+
+	case ALARM:
+		out = (data->alarms >> (sattr->index + 4)) & 1;
+		break;
+
+	case FAULT:
+		/* Note - only for remote1 and remote2 */
+		out = !!(data->alarms & (sattr->index ? 0x8000 : 0x4000));
+		break;
+
+	default:
+		/* All other temp values are in the configured format */
+		out = reg2temp(data, data->temp[sattr->nr][sattr->index]);
+	}
+
+	return sprintf(buf, "%d\n", out);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	unsigned char reg = 0;
+	u8 out;
+	int temp;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+
+	/* We need the config register in all cases for temp <-> reg conv. */
+	data->config5 = adt7475_read(REG_CONFIG5);
+
+	switch (sattr->nr) {
+	case OFFSET:
+		if (data->config5 & CONFIG5_TEMPOFFSET) {
+			val = clamp_val(val, -63000, 127000);
+			out = data->temp[OFFSET][sattr->index] = val / 1000;
+		} else {
+			val = clamp_val(val, -63000, 64000);
+			out = data->temp[OFFSET][sattr->index] = val / 500;
+		}
+		break;
+
+	case HYSTERSIS:
+		/*
+		 * The value will be given as an absolute value, turn it
+		 * into an offset based on THERM
+		 */
+
+		/* Read fresh THERM and HYSTERSIS values from the chip */
+		data->temp[THERM][sattr->index] =
+			adt7475_read(TEMP_THERM_REG(sattr->index)) << 2;
+		adt7475_read_hystersis(client);
+
+		temp = reg2temp(data, data->temp[THERM][sattr->index]);
+		val = clamp_val(val, temp - 15000, temp);
+		val = (temp - val) / 1000;
+
+		if (sattr->index != 1) {
+			data->temp[HYSTERSIS][sattr->index] &= 0xF0;
+			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4;
+		} else {
+			data->temp[HYSTERSIS][sattr->index] &= 0x0F;
+			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF);
+		}
+
+		out = data->temp[HYSTERSIS][sattr->index];
+		break;
+
+	default:
+		data->temp[sattr->nr][sattr->index] = temp2reg(data, val);
+
+		/*
+		 * We maintain an extra 2 digits of precision for simplicity
+		 * - shift those back off before writing the value
+		 */
+		out = (u8) (data->temp[sattr->nr][sattr->index] >> 2);
+	}
+
+	switch (sattr->nr) {
+	case MIN:
+		reg = TEMP_MIN_REG(sattr->index);
+		break;
+	case MAX:
+		reg = TEMP_MAX_REG(sattr->index);
+		break;
+	case OFFSET:
+		reg = TEMP_OFFSET_REG(sattr->index);
+		break;
+	case AUTOMIN:
+		reg = TEMP_TMIN_REG(sattr->index);
+		break;
+	case THERM:
+		reg = TEMP_THERM_REG(sattr->index);
+		break;
+	case HYSTERSIS:
+		if (sattr->index != 2)
+			reg = REG_REMOTE1_HYSTERSIS;
+		else
+			reg = REG_REMOTE2_HYSTERSIS;
+
+		break;
+	}
+
+	i2c_smbus_write_byte_data(client, reg, out);
+
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+/*
+ * Table of autorange values - the user will write the value in millidegrees,
+ * and we'll convert it
+ */
+static const int autorange_table[] = {
+	2000, 2500, 3330, 4000, 5000, 6670, 8000,
+	10000, 13330, 16000, 20000, 26670, 32000, 40000,
+	53330, 80000
+};
+
+static ssize_t show_point2(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int out, val;
+
+	mutex_lock(&data->lock);
+	out = (data->range[sattr->index] >> 4) & 0x0F;
+	val = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
+	mutex_unlock(&data->lock);
+
+	return sprintf(buf, "%d\n", val + autorange_table[out]);
+}
+
+static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int temp;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+
+	/* Get a fresh copy of the needed registers */
+	data->config5 = adt7475_read(REG_CONFIG5);
+	data->temp[AUTOMIN][sattr->index] =
+		adt7475_read(TEMP_TMIN_REG(sattr->index)) << 2;
+	data->range[sattr->index] =
+		adt7475_read(TEMP_TRANGE_REG(sattr->index));
+
+	/*
+	 * The user will write an absolute value, so subtract the start point
+	 * to figure the range
+	 */
+	temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
+	val = clamp_val(val, temp + autorange_table[0],
+		temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
+	val -= temp;
+
+	/* Find the nearest table entry to what the user wrote */
+	val = find_nearest(val, autorange_table, ARRAY_SIZE(autorange_table));
+
+	data->range[sattr->index] &= ~0xF0;
+	data->range[sattr->index] |= val << 4;
+
+	i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
+				  data->range[sattr->index]);
+
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static ssize_t show_tach(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int out;
+
+	if (sattr->nr == ALARM)
+		out = (data->alarms >> (sattr->index + 10)) & 1;
+	else
+		out = tach2rpm(data->tach[sattr->nr][sattr->index]);
+
+	return sprintf(buf, "%d\n", out);
+}
+
+static ssize_t set_tach(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+
+	data->tach[MIN][sattr->index] = rpm2tach(val);
+
+	adt7475_write_word(client, TACH_MIN_REG(sattr->index),
+			   data->tach[MIN][sattr->index]);
+
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n", data->pwm[sattr->nr][sattr->index]);
+}
+
+static ssize_t show_pwmchan(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n", data->pwmchan[sattr->index]);
+}
+
+static ssize_t show_pwmctrl(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n", data->pwmctl[sattr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	unsigned char reg = 0;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+
+	switch (sattr->nr) {
+	case INPUT:
+		/* Get a fresh value for CONTROL */
+		data->pwm[CONTROL][sattr->index] =
+			adt7475_read(PWM_CONFIG_REG(sattr->index));
+
+		/*
+		 * If we are not in manual mode, then we shouldn't allow
+		 * the user to set the pwm speed
+		 */
+		if (((data->pwm[CONTROL][sattr->index] >> 5) & 7) != 7) {
+			mutex_unlock(&data->lock);
+			return count;
+		}
+
+		reg = PWM_REG(sattr->index);
+		break;
+
+	case MIN:
+		reg = PWM_MIN_REG(sattr->index);
+		break;
+
+	case MAX:
+		reg = PWM_MAX_REG(sattr->index);
+		break;
+	}
+
+	data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
+	i2c_smbus_write_byte_data(client, reg,
+				  data->pwm[sattr->nr][sattr->index]);
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+/* Called by set_pwmctrl and set_pwmchan */
+
+static int hw_set_pwm(struct i2c_client *client, int index,
+		      unsigned int pwmctl, unsigned int pwmchan)
+{
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	long val = 0;
+
+	switch (pwmctl) {
+	case 0:
+		val = 0x03;	/* Run at full speed */
+		break;
+	case 1:
+		val = 0x07;	/* Manual mode */
+		break;
+	case 2:
+		switch (pwmchan) {
+		case 1:
+			/* Remote1 controls PWM */
+			val = 0x00;
+			break;
+		case 2:
+			/* local controls PWM */
+			val = 0x01;
+			break;
+		case 4:
+			/* remote2 controls PWM */
+			val = 0x02;
+			break;
+		case 6:
+			/* local/remote2 control PWM */
+			val = 0x05;
+			break;
+		case 7:
+			/* All three control PWM */
+			val = 0x06;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data->pwmctl[index] = pwmctl;
+	data->pwmchan[index] = pwmchan;
+
+	data->pwm[CONTROL][index] &= ~0xE0;
+	data->pwm[CONTROL][index] |= (val & 7) << 5;
+
+	i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+				  data->pwm[CONTROL][index]);
+
+	return 0;
+}
+
+static ssize_t set_pwmchan(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	int r;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	/* Read Modify Write PWM values */
+	adt7475_read_pwm(client, sattr->index);
+	r = hw_set_pwm(client, sattr->index, data->pwmctl[sattr->index], val);
+	if (r)
+		count = r;
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	int r;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	/* Read Modify Write PWM values */
+	adt7475_read_pwm(client, sattr->index);
+	r = hw_set_pwm(client, sattr->index, val, data->pwmchan[sattr->index]);
+	if (r)
+		count = r;
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+/* List of frequencies for the PWM */
+static const int pwmfreq_table[] = {
+	11, 14, 22, 29, 35, 44, 58, 88
+};
+
+static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n",
+		       pwmfreq_table[data->range[sattr->index] & 7]);
+}
+
+static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	int out;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	out = find_nearest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table));
+
+	mutex_lock(&data->lock);
+
+	data->range[sattr->index] =
+		adt7475_read(TEMP_TRANGE_REG(sattr->index));
+	data->range[sattr->index] &= ~7;
+	data->range[sattr->index] |= out;
+
+	i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
+				  data->range[sattr->index]);
+
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static ssize_t show_pwm_at_crit(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	return sprintf(buf, "%d\n", !!(data->config4 & CONFIG4_MAXDUTY));
+}
+
+static ssize_t set_pwm_at_crit(struct device *dev,
+			       struct device_attribute *devattr,
+			       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	data->config4 = i2c_smbus_read_byte_data(client, REG_CONFIG4);
+	if (val)
+		data->config4 |= CONFIG4_MAXDUTY;
+	else
+		data->config4 &= ~CONFIG4_MAXDUTY;
+	i2c_smbus_write_byte_data(client, REG_CONFIG4, data->config4);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct adt7475_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", (int)data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct adt7475_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+	if (val < 0 || val > 255)
+		return -EINVAL;
+	data->vrm = val;
+
+	return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct adt7475_data *data = adt7475_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_voltage, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 0);
+static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, show_voltage, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_voltage, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 1);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 1);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, show_voltage, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_voltage, NULL, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 2);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 2);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_voltage, NULL, ALARM, 2);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_voltage, NULL, INPUT, 3);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 3);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 3);
+static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, show_voltage, NULL, ALARM, 3);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_voltage, NULL, INPUT, 4);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 4);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 4);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, show_voltage, NULL, ALARM, 8);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_voltage, NULL, INPUT, 5);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MAX, 5);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_voltage,
+			    set_voltage, MIN, 5);
+static SENSOR_DEVICE_ATTR_2(in5_alarm, S_IRUGO, show_voltage, NULL, ALARM, 31);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_alarm, S_IRUGO, show_temp, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_temp, NULL, FAULT, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MAX, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MIN, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, OFFSET, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, set_temp, AUTOMIN, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_point2, set_point2, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    THERM, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, HYSTERSIS, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MAX, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MIN, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, OFFSET, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, set_temp, AUTOMIN, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_point2, set_point2, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    THERM, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, HYSTERSIS, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MAX, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    MIN, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, OFFSET, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, set_temp, AUTOMIN, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_point2, set_point2, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    THERM, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, HYSTERSIS, 2);
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+			    MIN, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_tach, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_tach, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+			    MIN, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_tach, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_tach, NULL, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+			    MIN, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_tach, NULL, ALARM, 2);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_tach, NULL, INPUT, 3);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+			    MIN, 3);
+static SENSOR_DEVICE_ATTR_2(fan4_alarm, S_IRUGO, show_tach, NULL, ALARM, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+			    0);
+static SENSOR_DEVICE_ATTR_2(pwm1_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+			    set_pwmfreq, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+			    set_pwmctrl, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
+			    show_pwmchan, set_pwmchan, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MIN, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MAX, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+			    1);
+static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+			    set_pwmfreq, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+			    set_pwmctrl, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
+			    show_pwmchan, set_pwmchan, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MIN, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MAX, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+			    2);
+static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+			    set_pwmfreq, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+			    set_pwmctrl, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
+			    show_pwmchan, set_pwmchan, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MIN, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+			    set_pwm, MAX, 2);
+
+/* Non-standard name, might need revisiting */
+static DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO,
+		   show_pwm_at_crit, set_pwm_at_crit);
+
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static struct attribute *adt7475_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&dev_attr_pwm_use_point2_pwm_at_crit.attr,
+	NULL,
+};
+
+static struct attribute *fan4_attrs[] = {
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *pwm2_attrs[] = {
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *in0_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *in3_attrs[] = {
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *in4_attrs[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *in5_attrs[] = {
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *vid_attrs[] = {
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	NULL
+};
+
+static struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs };
+static struct attribute_group fan4_attr_group = { .attrs = fan4_attrs };
+static struct attribute_group pwm2_attr_group = { .attrs = pwm2_attrs };
+static struct attribute_group in0_attr_group = { .attrs = in0_attrs };
+static struct attribute_group in3_attr_group = { .attrs = in3_attrs };
+static struct attribute_group in4_attr_group = { .attrs = in4_attrs };
+static struct attribute_group in5_attr_group = { .attrs = in5_attrs };
+static struct attribute_group vid_attr_group = { .attrs = vid_attrs };
+
+static int adt7475_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int vendid, devid, devid2;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	vendid = adt7475_read(REG_VENDID);
+	devid2 = adt7475_read(REG_DEVID2);
+	if (vendid != 0x41 ||		/* Analog Devices */
+	    (devid2 & 0xf8) != 0x68)
+		return -ENODEV;
+
+	devid = adt7475_read(REG_DEVID);
+	if (devid == 0x73)
+		name = "adt7473";
+	else if (devid == 0x75 && client->addr == 0x2e)
+		name = "adt7475";
+	else if (devid == 0x76)
+		name = "adt7476";
+	else if ((devid2 & 0xfc) == 0x6c)
+		name = "adt7490";
+	else {
+		dev_dbg(&adapter->dev,
+			"Couldn't detect an ADT7473/75/76/90 part at "
+			"0x%02x\n", (unsigned int)client->addr);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void adt7475_remove_files(struct i2c_client *client,
+				 struct adt7475_data *data)
+{
+	sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
+	if (data->has_fan4)
+		sysfs_remove_group(&client->dev.kobj, &fan4_attr_group);
+	if (data->has_pwm2)
+		sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group);
+	if (data->has_voltage & (1 << 0))
+		sysfs_remove_group(&client->dev.kobj, &in0_attr_group);
+	if (data->has_voltage & (1 << 3))
+		sysfs_remove_group(&client->dev.kobj, &in3_attr_group);
+	if (data->has_voltage & (1 << 4))
+		sysfs_remove_group(&client->dev.kobj, &in4_attr_group);
+	if (data->has_voltage & (1 << 5))
+		sysfs_remove_group(&client->dev.kobj, &in5_attr_group);
+	if (data->has_vid)
+		sysfs_remove_group(&client->dev.kobj, &vid_attr_group);
+}
+
+static int adt7475_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	static const char * const names[] = {
+		[adt7473] = "ADT7473",
+		[adt7475] = "ADT7475",
+		[adt7476] = "ADT7476",
+		[adt7490] = "ADT7490",
+	};
+
+	struct adt7475_data *data;
+	int i, ret = 0, revision;
+	u8 config2, config3;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	mutex_init(&data->lock);
+	i2c_set_clientdata(client, data);
+
+	/* Initialize device-specific values */
+	switch (id->driver_data) {
+	case adt7476:
+		data->has_voltage = 0x0e;	/* in1 to in3 */
+		revision = adt7475_read(REG_DEVID2) & 0x07;
+		break;
+	case adt7490:
+		data->has_voltage = 0x3e;	/* in1 to in5 */
+		revision = adt7475_read(REG_DEVID2) & 0x03;
+		if (revision == 0x03)
+			revision += adt7475_read(REG_DEVREV2);
+		break;
+	default:
+		data->has_voltage = 0x06;	/* in1, in2 */
+		revision = adt7475_read(REG_DEVID2) & 0x07;
+	}
+
+	config3 = adt7475_read(REG_CONFIG3);
+	/* Pin PWM2 may alternatively be used for ALERT output */
+	if (!(config3 & CONFIG3_SMBALERT))
+		data->has_pwm2 = 1;
+	/* Meaning of this bit is inverted for the ADT7473-1 */
+	if (id->driver_data == adt7473 && revision >= 1)
+		data->has_pwm2 = !data->has_pwm2;
+
+	data->config4 = adt7475_read(REG_CONFIG4);
+	/* Pin TACH4 may alternatively be used for THERM */
+	if ((data->config4 & CONFIG4_PINFUNC) == 0x0)
+		data->has_fan4 = 1;
+
+	/*
+	 * THERM configuration is more complex on the ADT7476 and ADT7490,
+	 * because 2 different pins (TACH4 and +2.5 Vin) can be used for
+	 * this function
+	 */
+	if (id->driver_data == adt7490) {
+		if ((data->config4 & CONFIG4_PINFUNC) == 0x1 &&
+		    !(config3 & CONFIG3_THERM))
+			data->has_fan4 = 1;
+	}
+	if (id->driver_data == adt7476 || id->driver_data == adt7490) {
+		if (!(config3 & CONFIG3_THERM) ||
+		    (data->config4 & CONFIG4_PINFUNC) == 0x1)
+			data->has_voltage |= (1 << 0);		/* in0 */
+	}
+
+	/*
+	 * On the ADT7476, the +12V input pin may instead be used as VID5,
+	 * and VID pins may alternatively be used as GPIO
+	 */
+	if (id->driver_data == adt7476) {
+		u8 vid = adt7475_read(REG_VID);
+		if (!(vid & VID_VIDSEL))
+			data->has_voltage |= (1 << 4);		/* in4 */
+
+		data->has_vid = !(adt7475_read(REG_CONFIG5) & CONFIG5_VIDGPIO);
+	}
+
+	/* Voltage attenuators can be bypassed, globally or individually */
+	config2 = adt7475_read(REG_CONFIG2);
+	if (config2 & CONFIG2_ATTN) {
+		data->bypass_attn = (0x3 << 3) | 0x3;
+	} else {
+		data->bypass_attn = ((data->config4 & CONFIG4_ATTN_IN10) >> 4) |
+				    ((data->config4 & CONFIG4_ATTN_IN43) >> 3);
+	}
+	data->bypass_attn &= data->has_voltage;
+
+	/*
+	 * Call adt7475_read_pwm for all pwm's as this will reprogram any
+	 * pwm's which are disabled to manual mode with 0% duty cycle
+	 */
+	for (i = 0; i < ADT7475_PWM_COUNT; i++)
+		adt7475_read_pwm(client, i);
+
+	ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
+	if (ret)
+		return ret;
+
+	/* Features that can be disabled individually */
+	if (data->has_fan4) {
+		ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_pwm2) {
+		ret = sysfs_create_group(&client->dev.kobj, &pwm2_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_voltage & (1 << 0)) {
+		ret = sysfs_create_group(&client->dev.kobj, &in0_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_voltage & (1 << 3)) {
+		ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_voltage & (1 << 4)) {
+		ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_voltage & (1 << 5)) {
+		ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group);
+		if (ret)
+			goto eremove;
+	}
+	if (data->has_vid) {
+		data->vrm = vid_which_vrm();
+		ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group);
+		if (ret)
+			goto eremove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto eremove;
+	}
+
+	dev_info(&client->dev, "%s device, revision %d\n",
+		 names[id->driver_data], revision);
+	if ((data->has_voltage & 0x11) || data->has_fan4 || data->has_pwm2)
+		dev_info(&client->dev, "Optional features:%s%s%s%s%s\n",
+			 (data->has_voltage & (1 << 0)) ? " in0" : "",
+			 (data->has_voltage & (1 << 4)) ? " in4" : "",
+			 data->has_fan4 ? " fan4" : "",
+			 data->has_pwm2 ? " pwm2" : "",
+			 data->has_vid ? " vid" : "");
+	if (data->bypass_attn)
+		dev_info(&client->dev, "Bypassing attenuators on:%s%s%s%s\n",
+			 (data->bypass_attn & (1 << 0)) ? " in0" : "",
+			 (data->bypass_attn & (1 << 1)) ? " in1" : "",
+			 (data->bypass_attn & (1 << 3)) ? " in3" : "",
+			 (data->bypass_attn & (1 << 4)) ? " in4" : "");
+
+	return 0;
+
+eremove:
+	adt7475_remove_files(client, data);
+	return ret;
+}
+
+static int adt7475_remove(struct i2c_client *client)
+{
+	struct adt7475_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	adt7475_remove_files(client, data);
+
+	return 0;
+}
+
+static struct i2c_driver adt7475_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7475",
+	},
+	.probe		= adt7475_probe,
+	.remove		= adt7475_remove,
+	.id_table	= adt7475_id,
+	.detect		= adt7475_detect,
+	.address_list	= normal_i2c,
+};
+
+static void adt7475_read_hystersis(struct i2c_client *client)
+{
+	struct adt7475_data *data = i2c_get_clientdata(client);
+
+	data->temp[HYSTERSIS][0] = (u16) adt7475_read(REG_REMOTE1_HYSTERSIS);
+	data->temp[HYSTERSIS][1] = data->temp[HYSTERSIS][0];
+	data->temp[HYSTERSIS][2] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS);
+}
+
+static void adt7475_read_pwm(struct i2c_client *client, int index)
+{
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	unsigned int v;
+
+	data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index));
+
+	/*
+	 * Figure out the internal value for pwmctrl and pwmchan
+	 * based on the current settings
+	 */
+	v = (data->pwm[CONTROL][index] >> 5) & 7;
+
+	if (v == 3)
+		data->pwmctl[index] = 0;
+	else if (v == 7)
+		data->pwmctl[index] = 1;
+	else if (v == 4) {
+		/*
+		 * The fan is disabled - we don't want to
+		 * support that, so change to manual mode and
+		 * set the duty cycle to 0 instead
+		 */
+		data->pwm[INPUT][index] = 0;
+		data->pwm[CONTROL][index] &= ~0xE0;
+		data->pwm[CONTROL][index] |= (7 << 5);
+
+		i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+					  data->pwm[INPUT][index]);
+
+		i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+					  data->pwm[CONTROL][index]);
+
+		data->pwmctl[index] = 1;
+	} else {
+		data->pwmctl[index] = 2;
+
+		switch (v) {
+		case 0:
+			data->pwmchan[index] = 1;
+			break;
+		case 1:
+			data->pwmchan[index] = 2;
+			break;
+		case 2:
+			data->pwmchan[index] = 4;
+			break;
+		case 5:
+			data->pwmchan[index] = 6;
+			break;
+		case 6:
+			data->pwmchan[index] = 7;
+			break;
+		}
+	}
+}
+
+static struct adt7475_data *adt7475_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7475_data *data = i2c_get_clientdata(client);
+	u16 ext;
+	int i;
+
+	mutex_lock(&data->lock);
+
+	/* Measurement values update every 2 seconds */
+	if (time_after(jiffies, data->measure_updated + HZ * 2) ||
+	    !data->valid) {
+		data->alarms = adt7475_read(REG_STATUS2) << 8;
+		data->alarms |= adt7475_read(REG_STATUS1);
+
+		ext = (adt7475_read(REG_EXTEND2) << 8) |
+			adt7475_read(REG_EXTEND1);
+		for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++) {
+			if (!(data->has_voltage & (1 << i)))
+				continue;
+			data->voltage[INPUT][i] =
+				(adt7475_read(VOLTAGE_REG(i)) << 2) |
+				((ext >> (i * 2)) & 3);
+		}
+
+		for (i = 0; i < ADT7475_TEMP_COUNT; i++)
+			data->temp[INPUT][i] =
+				(adt7475_read(TEMP_REG(i)) << 2) |
+				((ext >> ((i + 5) * 2)) & 3);
+
+		if (data->has_voltage & (1 << 5)) {
+			data->alarms |= adt7475_read(REG_STATUS4) << 24;
+			ext = adt7475_read(REG_EXTEND3);
+			data->voltage[INPUT][5] = adt7475_read(REG_VTT) << 2 |
+				((ext >> 4) & 3);
+		}
+
+		for (i = 0; i < ADT7475_TACH_COUNT; i++) {
+			if (i == 3 && !data->has_fan4)
+				continue;
+			data->tach[INPUT][i] =
+				adt7475_read_word(client, TACH_REG(i));
+		}
+
+		/* Updated by hw when in auto mode */
+		for (i = 0; i < ADT7475_PWM_COUNT; i++) {
+			if (i == 1 && !data->has_pwm2)
+				continue;
+			data->pwm[INPUT][i] = adt7475_read(PWM_REG(i));
+		}
+
+		if (data->has_vid)
+			data->vid = adt7475_read(REG_VID) & 0x3f;
+
+		data->measure_updated = jiffies;
+	}
+
+	/* Limits and settings, should never change update every 60 seconds */
+	if (time_after(jiffies, data->limits_updated + HZ * 60) ||
+	    !data->valid) {
+		data->config4 = adt7475_read(REG_CONFIG4);
+		data->config5 = adt7475_read(REG_CONFIG5);
+
+		for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++) {
+			if (!(data->has_voltage & (1 << i)))
+				continue;
+			/* Adjust values so they match the input precision */
+			data->voltage[MIN][i] =
+				adt7475_read(VOLTAGE_MIN_REG(i)) << 2;
+			data->voltage[MAX][i] =
+				adt7475_read(VOLTAGE_MAX_REG(i)) << 2;
+		}
+
+		if (data->has_voltage & (1 << 5)) {
+			data->voltage[MIN][5] = adt7475_read(REG_VTT_MIN) << 2;
+			data->voltage[MAX][5] = adt7475_read(REG_VTT_MAX) << 2;
+		}
+
+		for (i = 0; i < ADT7475_TEMP_COUNT; i++) {
+			/* Adjust values so they match the input precision */
+			data->temp[MIN][i] =
+				adt7475_read(TEMP_MIN_REG(i)) << 2;
+			data->temp[MAX][i] =
+				adt7475_read(TEMP_MAX_REG(i)) << 2;
+			data->temp[AUTOMIN][i] =
+				adt7475_read(TEMP_TMIN_REG(i)) << 2;
+			data->temp[THERM][i] =
+				adt7475_read(TEMP_THERM_REG(i)) << 2;
+			data->temp[OFFSET][i] =
+				adt7475_read(TEMP_OFFSET_REG(i));
+		}
+		adt7475_read_hystersis(client);
+
+		for (i = 0; i < ADT7475_TACH_COUNT; i++) {
+			if (i == 3 && !data->has_fan4)
+				continue;
+			data->tach[MIN][i] =
+				adt7475_read_word(client, TACH_MIN_REG(i));
+		}
+
+		for (i = 0; i < ADT7475_PWM_COUNT; i++) {
+			if (i == 1 && !data->has_pwm2)
+				continue;
+			data->pwm[MAX][i] = adt7475_read(PWM_MAX_REG(i));
+			data->pwm[MIN][i] = adt7475_read(PWM_MIN_REG(i));
+			/* Set the channel and control information */
+			adt7475_read_pwm(client, i);
+		}
+
+		data->range[0] = adt7475_read(TEMP_TRANGE_REG(0));
+		data->range[1] = adt7475_read(TEMP_TRANGE_REG(1));
+		data->range[2] = adt7475_read(TEMP_TRANGE_REG(2));
+
+		data->limits_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+module_i2c_driver(adt7475_driver);
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("adt7475 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
new file mode 100644
index 0000000..98141f4
--- /dev/null
+++ b/drivers/hwmon/adt7x10.c
@@ -0,0 +1,511 @@
+/*
+ * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * 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/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "adt7x10.h"
+
+/*
+ * ADT7X10 status
+ */
+#define ADT7X10_STAT_T_LOW		(1 << 4)
+#define ADT7X10_STAT_T_HIGH		(1 << 5)
+#define ADT7X10_STAT_T_CRIT		(1 << 6)
+#define ADT7X10_STAT_NOT_RDY		(1 << 7)
+
+/*
+ * ADT7X10 config
+ */
+#define ADT7X10_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
+#define ADT7X10_CT_POLARITY		(1 << 2)
+#define ADT7X10_INT_POLARITY		(1 << 3)
+#define ADT7X10_EVENT_MODE		(1 << 4)
+#define ADT7X10_MODE_MASK		(1 << 5 | 1 << 6)
+#define ADT7X10_FULL			(0 << 5 | 0 << 6)
+#define ADT7X10_PD			(1 << 5 | 1 << 6)
+#define ADT7X10_RESOLUTION		(1 << 7)
+
+/*
+ * ADT7X10 masks
+ */
+#define ADT7X10_T13_VALUE_MASK		0xFFF8
+#define ADT7X10_T_HYST_MASK		0xF
+
+/* straight from the datasheet */
+#define ADT7X10_TEMP_MIN (-55000)
+#define ADT7X10_TEMP_MAX 150000
+
+/* Each client has this additional data */
+struct adt7x10_data {
+	const struct adt7x10_ops *ops;
+	const char		*name;
+	struct device		*hwmon_dev;
+	struct mutex		update_lock;
+	u8			config;
+	u8			oldconfig;
+	bool			valid;		/* true if registers valid */
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[4];	/* Register values,
+						   0 = input
+						   1 = high
+						   2 = low
+						   3 = critical */
+	u8			hyst;		/* hysteresis offset */
+};
+
+static int adt7x10_read_byte(struct device *dev, u8 reg)
+{
+	struct adt7x10_data *d = dev_get_drvdata(dev);
+	return d->ops->read_byte(dev, reg);
+}
+
+static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data)
+{
+	struct adt7x10_data *d = dev_get_drvdata(dev);
+	return d->ops->write_byte(dev, reg, data);
+}
+
+static int adt7x10_read_word(struct device *dev, u8 reg)
+{
+	struct adt7x10_data *d = dev_get_drvdata(dev);
+	return d->ops->read_word(dev, reg);
+}
+
+static int adt7x10_write_word(struct device *dev, u8 reg, u16 data)
+{
+	struct adt7x10_data *d = dev_get_drvdata(dev);
+	return d->ops->write_word(dev, reg, data);
+}
+
+static const u8 ADT7X10_REG_TEMP[4] = {
+	ADT7X10_TEMPERATURE,		/* input */
+	ADT7X10_T_ALARM_HIGH,		/* high */
+	ADT7X10_T_ALARM_LOW,		/* low */
+	ADT7X10_T_CRIT,			/* critical */
+};
+
+static irqreturn_t adt7x10_irq_handler(int irq, void *private)
+{
+	struct device *dev = private;
+	int status;
+
+	status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+	if (status < 0)
+		return IRQ_HANDLED;
+
+	if (status & ADT7X10_STAT_T_HIGH)
+		sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
+	if (status & ADT7X10_STAT_T_LOW)
+		sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
+	if (status & ADT7X10_STAT_T_CRIT)
+		sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
+
+	return IRQ_HANDLED;
+}
+
+static int adt7x10_temp_ready(struct device *dev)
+{
+	int i, status;
+
+	for (i = 0; i < 6; i++) {
+		status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+		if (status < 0)
+			return status;
+		if (!(status & ADT7X10_STAT_NOT_RDY))
+			return 0;
+		msleep(60);
+	}
+	return -ETIMEDOUT;
+}
+
+static int adt7x10_update_temp(struct device *dev)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int temp;
+
+		dev_dbg(dev, "Starting update\n");
+
+		ret = adt7x10_temp_ready(dev); /* check for new value */
+		if (ret)
+			goto abort;
+
+		temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]);
+		if (temp < 0) {
+			ret = temp;
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7X10_REG_TEMP[0], ret);
+			goto abort;
+		}
+		data->temp[0] = temp;
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static int adt7x10_fill_cache(struct device *dev)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+	int ret;
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
+		ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]);
+		if (ret < 0) {
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7X10_REG_TEMP[i], ret);
+			return ret;
+		}
+		data->temp[i] = ret;
+	}
+
+	ret = adt7x10_read_byte(dev, ADT7X10_T_HYST);
+	if (ret < 0) {
+		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7X10_T_HYST, ret);
+		return ret;
+	}
+	data->hyst = ret;
+
+	return 0;
+}
+
+static s16 ADT7X10_TEMP_TO_REG(long temp)
+{
+	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
+					       ADT7X10_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
+{
+	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
+	if (!(data->config & ADT7X10_RESOLUTION))
+		reg &= ADT7X10_T13_VALUE_MASK;
+	/*
+	 * temperature is stored in twos complement format, in steps of
+	 * 1/128°C
+	 */
+	return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7x10_show_temp(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+
+
+	if (attr->index == 0) {
+		int ret;
+
+		ret = adt7x10_update_temp(dev);
+		if (ret)
+			return ret;
+	}
+
+	return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data,
+		       data->temp[attr->index]));
+}
+
+static ssize_t adt7x10_set_temp(struct device *dev,
+				struct device_attribute *da,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = ADT7X10_TEMP_TO_REG(temp);
+	ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]);
+	if (ret)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t adt7x10_show_t_hyst(struct device *dev,
+				   struct device_attribute *da,
+				   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	int hyst;
+
+	hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000;
+
+	/*
+	 * hysteresis is stored as a 4 bit offset in the device, convert it
+	 * to an absolute value
+	 */
+	if (nr == 2)	/* min has positive offset, others have negative */
+		hyst = -hyst;
+	return sprintf(buf, "%d\n",
+		       ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7x10_set_t_hyst(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+	int limit, ret;
+	long hyst;
+
+	ret = kstrtol(buf, 10, &hyst);
+	if (ret)
+		return ret;
+	/* convert absolute hysteresis value to a 4 bit delta value */
+	limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]);
+	hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
+	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+				   0, ADT7X10_T_HYST_MASK);
+	ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t adt7x10_show_alarm(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int ret;
+
+	ret = adt7x10_read_byte(dev, ADT7X10_STATUS);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static ssize_t adt7x10_show_name(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7x10_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  adt7x10_show_temp, adt7x10_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  adt7x10_show_temp, adt7x10_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+			  adt7x10_show_temp, adt7x10_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  adt7x10_show_t_hyst, adt7x10_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+			  adt7x10_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+			  adt7x10_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7x10_show_alarm,
+			  NULL, ADT7X10_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm,
+			  NULL, ADT7X10_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm,
+			  NULL, ADT7X10_STAT_T_CRIT);
+static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL);
+
+static struct attribute *adt7x10_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adt7x10_group = {
+	.attrs = adt7x10_attributes,
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+		  const struct adt7x10_ops *ops)
+{
+	struct adt7x10_data *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->ops = ops;
+	data->name = name;
+
+	dev_set_drvdata(dev, data);
+	mutex_init(&data->update_lock);
+
+	/* configure as specified */
+	ret = adt7x10_read_byte(dev, ADT7X10_CONFIG);
+	if (ret < 0) {
+		dev_dbg(dev, "Can't read config? %d\n", ret);
+		return ret;
+	}
+	data->oldconfig = ret;
+
+	/*
+	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 */
+	data->config = data->oldconfig;
+	data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
+			ADT7X10_INT_POLARITY);
+	data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
+
+	if (data->config != data->oldconfig) {
+		ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+		if (ret)
+			return ret;
+	}
+	dev_dbg(dev, "Config %02x\n", data->config);
+
+	ret = adt7x10_fill_cache(dev);
+	if (ret)
+		goto exit_restore;
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&dev->kobj, &adt7x10_group);
+	if (ret)
+		goto exit_restore;
+
+	/*
+	 * The I2C device will already have it's own 'name' attribute, but for
+	 * the SPI device we need to register it. name will only be non NULL if
+	 * the device doesn't register the 'name' attribute on its own.
+	 */
+	if (name) {
+		ret = device_create_file(dev, &dev_attr_name);
+		if (ret)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_name;
+	}
+
+	if (irq > 0) {
+		ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler,
+				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				dev_name(dev), dev);
+		if (ret)
+			goto exit_hwmon_device_unregister;
+	}
+
+	return 0;
+
+exit_hwmon_device_unregister:
+	hwmon_device_unregister(data->hwmon_dev);
+exit_remove_name:
+	if (name)
+		device_remove_file(dev, &dev_attr_name);
+exit_remove:
+	sysfs_remove_group(&dev->kobj, &adt7x10_group);
+exit_restore:
+	adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(adt7x10_probe);
+
+int adt7x10_remove(struct device *dev, int irq)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+
+	if (irq > 0)
+		free_irq(irq, dev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	if (data->name)
+		device_remove_file(dev, &dev_attr_name);
+	sysfs_remove_group(&dev->kobj, &adt7x10_group);
+	if (data->oldconfig != data->config)
+		adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adt7x10_remove);
+
+#ifdef CONFIG_PM_SLEEP
+
+static int adt7x10_suspend(struct device *dev)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+
+	return adt7x10_write_byte(dev, ADT7X10_CONFIG,
+		data->config | ADT7X10_PD);
+}
+
+static int adt7x10_resume(struct device *dev)
+{
+	struct adt7x10_data *data = dev_get_drvdata(dev);
+
+	return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+}
+
+SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
+EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
+
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
new file mode 100644
index 0000000..d491c69
--- /dev/null
+++ b/drivers/hwmon/adt7x10.h
@@ -0,0 +1,37 @@
+#ifndef __HWMON_ADT7X10_H__
+#define __HWMON_ADT7X10_H__
+
+#include <linux/types.h>
+#include <linux/pm.h>
+
+/* ADT7410 registers definition */
+#define ADT7X10_TEMPERATURE		0
+#define ADT7X10_STATUS			2
+#define ADT7X10_CONFIG			3
+#define ADT7X10_T_ALARM_HIGH		4
+#define ADT7X10_T_ALARM_LOW		6
+#define ADT7X10_T_CRIT			8
+#define ADT7X10_T_HYST			0xA
+#define ADT7X10_ID			0xB
+
+struct device;
+
+struct adt7x10_ops {
+	int (*read_byte)(struct device *, u8 reg);
+	int (*write_byte)(struct device *, u8 reg, u8 data);
+	int (*read_word)(struct device *, u8 reg);
+	int (*write_word)(struct device *, u8 reg, u16 data);
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+	const struct adt7x10_ops *ops);
+int adt7x10_remove(struct device *dev, int irq);
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops adt7x10_dev_pm_ops;
+#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops)
+#else
+#define ADT7X10_DEV_PM_OPS NULL
+#endif
+
+#endif
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
new file mode 100644
index 0000000..46b4e35
--- /dev/null
+++ b/drivers/hwmon/amc6821.c
@@ -0,0 +1,1021 @@
+/*
+ * amc6821.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
+ *
+ * Based on max6650.c:
+ * Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
+ *
+ * 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>	/* Needed for KERN_INFO */
+#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>
+
+/*
+ * Addresses to scan.
+ */
+
+static const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e,
+	0x4c, 0x4d, 0x4e, I2C_CLIENT_END};
+
+/*
+ * Insmod parameters
+ */
+
+static int pwminv;	/*Inverted PWM output. */
+module_param(pwminv, int, S_IRUGO);
+
+static int init = 1; /*Power-on initialization.*/
+module_param(init, int, S_IRUGO);
+
+enum chips { amc6821 };
+
+#define AMC6821_REG_DEV_ID 0x3D
+#define AMC6821_REG_COMP_ID 0x3E
+#define AMC6821_REG_CONF1 0x00
+#define AMC6821_REG_CONF2 0x01
+#define AMC6821_REG_CONF3 0x3F
+#define AMC6821_REG_CONF4 0x04
+#define AMC6821_REG_STAT1 0x02
+#define AMC6821_REG_STAT2 0x03
+#define AMC6821_REG_TDATA_LOW 0x08
+#define AMC6821_REG_TDATA_HI 0x09
+#define AMC6821_REG_LTEMP_HI 0x0A
+#define AMC6821_REG_RTEMP_HI 0x0B
+#define AMC6821_REG_LTEMP_LIMIT_MIN 0x15
+#define AMC6821_REG_LTEMP_LIMIT_MAX 0x14
+#define AMC6821_REG_RTEMP_LIMIT_MIN 0x19
+#define AMC6821_REG_RTEMP_LIMIT_MAX 0x18
+#define AMC6821_REG_LTEMP_CRIT 0x1B
+#define AMC6821_REG_RTEMP_CRIT 0x1D
+#define AMC6821_REG_PSV_TEMP 0x1C
+#define AMC6821_REG_DCY 0x22
+#define AMC6821_REG_LTEMP_FAN_CTRL 0x24
+#define AMC6821_REG_RTEMP_FAN_CTRL 0x25
+#define AMC6821_REG_DCY_LOW_TEMP 0x21
+
+#define AMC6821_REG_TACH_LLIMITL 0x10
+#define AMC6821_REG_TACH_LLIMITH 0x11
+#define AMC6821_REG_TACH_HLIMITL 0x12
+#define AMC6821_REG_TACH_HLIMITH 0x13
+
+#define AMC6821_CONF1_START 0x01
+#define AMC6821_CONF1_FAN_INT_EN 0x02
+#define AMC6821_CONF1_FANIE 0x04
+#define AMC6821_CONF1_PWMINV 0x08
+#define AMC6821_CONF1_FAN_FAULT_EN 0x10
+#define AMC6821_CONF1_FDRC0 0x20
+#define AMC6821_CONF1_FDRC1 0x40
+#define AMC6821_CONF1_THERMOVIE 0x80
+
+#define AMC6821_CONF2_PWM_EN 0x01
+#define AMC6821_CONF2_TACH_MODE 0x02
+#define AMC6821_CONF2_TACH_EN 0x04
+#define AMC6821_CONF2_RTFIE 0x08
+#define AMC6821_CONF2_LTOIE 0x10
+#define AMC6821_CONF2_RTOIE 0x20
+#define AMC6821_CONF2_PSVIE 0x40
+#define AMC6821_CONF2_RST 0x80
+
+#define AMC6821_CONF3_THERM_FAN_EN 0x80
+#define AMC6821_CONF3_REV_MASK 0x0F
+
+#define AMC6821_CONF4_OVREN 0x10
+#define AMC6821_CONF4_TACH_FAST 0x20
+#define AMC6821_CONF4_PSPR 0x40
+#define AMC6821_CONF4_MODE 0x80
+
+#define AMC6821_STAT1_RPM_ALARM 0x01
+#define AMC6821_STAT1_FANS 0x02
+#define AMC6821_STAT1_RTH 0x04
+#define AMC6821_STAT1_RTL 0x08
+#define AMC6821_STAT1_R_THERM 0x10
+#define AMC6821_STAT1_RTF 0x20
+#define AMC6821_STAT1_LTH 0x40
+#define AMC6821_STAT1_LTL 0x80
+
+#define AMC6821_STAT2_RTC 0x08
+#define AMC6821_STAT2_LTC 0x10
+#define AMC6821_STAT2_LPSV 0x20
+#define AMC6821_STAT2_L_THERM 0x40
+#define AMC6821_STAT2_THERM_IN 0x80
+
+enum {IDX_TEMP1_INPUT = 0, IDX_TEMP1_MIN, IDX_TEMP1_MAX,
+	IDX_TEMP1_CRIT, IDX_TEMP2_INPUT, IDX_TEMP2_MIN,
+	IDX_TEMP2_MAX, IDX_TEMP2_CRIT,
+	TEMP_IDX_LEN, };
+
+static const u8 temp_reg[] = {AMC6821_REG_LTEMP_HI,
+			AMC6821_REG_LTEMP_LIMIT_MIN,
+			AMC6821_REG_LTEMP_LIMIT_MAX,
+			AMC6821_REG_LTEMP_CRIT,
+			AMC6821_REG_RTEMP_HI,
+			AMC6821_REG_RTEMP_LIMIT_MIN,
+			AMC6821_REG_RTEMP_LIMIT_MAX,
+			AMC6821_REG_RTEMP_CRIT, };
+
+enum {IDX_FAN1_INPUT = 0, IDX_FAN1_MIN, IDX_FAN1_MAX,
+	FAN1_IDX_LEN, };
+
+static const u8 fan_reg_low[] = {AMC6821_REG_TDATA_LOW,
+			AMC6821_REG_TACH_LLIMITL,
+			AMC6821_REG_TACH_HLIMITL, };
+
+
+static const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI,
+			AMC6821_REG_TACH_LLIMITH,
+			AMC6821_REG_TACH_HLIMITH, };
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct amc6821_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	int temp[TEMP_IDX_LEN];
+
+	u16 fan[FAN1_IDX_LEN];
+	u8 fan1_div;
+
+	u8 pwm1;
+	u8 temp1_auto_point_temp[3];
+	u8 temp2_auto_point_temp[3];
+	u8 pwm1_auto_point_pwm[3];
+	u8 pwm1_enable;
+	u8 pwm1_auto_channels_temp;
+
+	u8 stat1;
+	u8 stat2;
+};
+
+static struct amc6821_data *amc6821_update_device(struct device *dev)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int timeout = HZ;
+	u8 reg;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + timeout) ||
+			!data->valid) {
+
+		for (i = 0; i < TEMP_IDX_LEN; i++)
+			data->temp[i] = (int8_t)i2c_smbus_read_byte_data(
+				client, temp_reg[i]);
+
+		data->stat1 = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_STAT1);
+		data->stat2 = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_STAT2);
+
+		data->pwm1 = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_DCY);
+		for (i = 0; i < FAN1_IDX_LEN; i++) {
+			data->fan[i] = i2c_smbus_read_byte_data(
+					client,
+					fan_reg_low[i]);
+			data->fan[i] += i2c_smbus_read_byte_data(
+					client,
+					fan_reg_hi[i]) << 8;
+		}
+		data->fan1_div = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_CONF4);
+		data->fan1_div = data->fan1_div & AMC6821_CONF4_PSPR ? 4 : 2;
+
+		data->pwm1_auto_point_pwm[0] = 0;
+		data->pwm1_auto_point_pwm[2] = 255;
+		data->pwm1_auto_point_pwm[1] = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_DCY_LOW_TEMP);
+
+		data->temp1_auto_point_temp[0] =
+			i2c_smbus_read_byte_data(client,
+					AMC6821_REG_PSV_TEMP);
+		data->temp2_auto_point_temp[0] =
+				data->temp1_auto_point_temp[0];
+		reg = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_LTEMP_FAN_CTRL);
+		data->temp1_auto_point_temp[1] = (reg & 0xF8) >> 1;
+		reg &= 0x07;
+		reg = 0x20 >> reg;
+		if (reg > 0)
+			data->temp1_auto_point_temp[2] =
+				data->temp1_auto_point_temp[1] +
+				(data->pwm1_auto_point_pwm[2] -
+				data->pwm1_auto_point_pwm[1]) / reg;
+		else
+			data->temp1_auto_point_temp[2] = 255;
+
+		reg = i2c_smbus_read_byte_data(client,
+			AMC6821_REG_RTEMP_FAN_CTRL);
+		data->temp2_auto_point_temp[1] = (reg & 0xF8) >> 1;
+		reg &= 0x07;
+		reg = 0x20 >> reg;
+		if (reg > 0)
+			data->temp2_auto_point_temp[2] =
+				data->temp2_auto_point_temp[1] +
+				(data->pwm1_auto_point_pwm[2] -
+				data->pwm1_auto_point_pwm[1]) / reg;
+		else
+			data->temp2_auto_point_temp[2] = 255;
+
+		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+		reg = (reg >> 5) & 0x3;
+		switch (reg) {
+		case 0: /*open loop: software sets pwm1*/
+			data->pwm1_auto_channels_temp = 0;
+			data->pwm1_enable = 1;
+			break;
+		case 2: /*closed loop: remote T (temp2)*/
+			data->pwm1_auto_channels_temp = 2;
+			data->pwm1_enable = 2;
+			break;
+		case 3: /*closed loop: local and remote T (temp2)*/
+			data->pwm1_auto_channels_temp = 3;
+			data->pwm1_enable = 3;
+			break;
+		case 1: /*
+			 * semi-open loop: software sets rpm, chip controls
+			 * pwm1, currently not implemented
+			 */
+			data->pwm1_auto_channels_temp = 0;
+			data->pwm1_enable = 0;
+			break;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static ssize_t get_temp(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->temp[ix] * 1000);
+}
+
+static ssize_t set_temp(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ix = to_sensor_dev_attr(attr)->index;
+	long val;
+
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = clamp_val(val / 1000, -128, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp[ix] = val;
+	if (i2c_smbus_write_byte_data(client, temp_reg[ix], data->temp[ix])) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_temp_alarm(
+	struct device *dev,
+	struct device_attribute *devattr,
+	char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+	u8 flag;
+
+	switch (ix) {
+	case IDX_TEMP1_MIN:
+		flag = data->stat1 & AMC6821_STAT1_LTL;
+		break;
+	case IDX_TEMP1_MAX:
+		flag = data->stat1 & AMC6821_STAT1_LTH;
+		break;
+	case IDX_TEMP1_CRIT:
+		flag = data->stat2 & AMC6821_STAT2_LTC;
+		break;
+	case IDX_TEMP2_MIN:
+		flag = data->stat1 & AMC6821_STAT1_RTL;
+		break;
+	case IDX_TEMP2_MAX:
+		flag = data->stat1 & AMC6821_STAT1_RTH;
+		break;
+	case IDX_TEMP2_CRIT:
+		flag = data->stat2 & AMC6821_STAT2_RTC;
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
+		return -EINVAL;
+	}
+	if (flag)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+static ssize_t get_temp2_fault(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	if (data->stat1 & AMC6821_STAT1_RTF)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+static ssize_t get_pwm1(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1);
+}
+
+static ssize_t set_pwm1(
+		struct device *dev,
+		struct device_attribute *devattr,
+		const char *buf,
+		size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1 = clamp_val(val , 0, 255);
+	i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_pwm1_enable(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_enable);
+}
+
+static ssize_t set_pwm1_enable(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int config = kstrtol(buf, 10, &val);
+	if (config)
+		return config;
+
+	mutex_lock(&data->update_lock);
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+	if (config < 0) {
+			dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+			count = config;
+			goto unlock;
+	}
+
+	switch (val) {
+	case 1:
+		config &= ~AMC6821_CONF1_FDRC0;
+		config &= ~AMC6821_CONF1_FDRC1;
+		break;
+	case 2:
+		config &= ~AMC6821_CONF1_FDRC0;
+		config |= AMC6821_CONF1_FDRC1;
+		break;
+	case 3:
+		config |= AMC6821_CONF1_FDRC0;
+		config |= AMC6821_CONF1_FDRC1;
+		break;
+	default:
+		count = -EINVAL;
+		goto unlock;
+	}
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			count = -EIO;
+	}
+unlock:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_pwm1_auto_channels_temp(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_auto_channels_temp);
+}
+
+static ssize_t get_temp_auto_point_temp(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	int ix = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	struct amc6821_data *data = amc6821_update_device(dev);
+	switch (nr) {
+	case 1:
+		return sprintf(buf, "%d\n",
+			data->temp1_auto_point_temp[ix] * 1000);
+	case 2:
+		return sprintf(buf, "%d\n",
+			data->temp2_auto_point_temp[ix] * 1000);
+	default:
+		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
+		return -EINVAL;
+	}
+}
+
+static ssize_t get_pwm1_auto_point_pwm(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	int ix = to_sensor_dev_attr(devattr)->index;
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[ix]);
+}
+
+static inline ssize_t set_slope_register(struct i2c_client *client,
+		u8 reg,
+		u8 dpwm,
+		u8 *ptemp)
+{
+	int dt;
+	u8 tmp;
+
+	dt = ptemp[2]-ptemp[1];
+	for (tmp = 4; tmp > 0; tmp--) {
+		if (dt * (0x20 >> tmp) >= dpwm)
+			break;
+	}
+	tmp |= (ptemp[1] & 0x7C) << 1;
+	if (i2c_smbus_write_byte_data(client,
+			reg, tmp)) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static ssize_t set_temp_auto_point_temp(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	struct i2c_client *client = data->client;
+	int ix = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	u8 *ptemp;
+	u8 reg;
+	int dpwm;
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	switch (nr) {
+	case 1:
+		ptemp = data->temp1_auto_point_temp;
+		reg = AMC6821_REG_LTEMP_FAN_CTRL;
+		break;
+	case 2:
+		ptemp = data->temp2_auto_point_temp;
+		reg = AMC6821_REG_RTEMP_FAN_CTRL;
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->valid = 0;
+
+	switch (ix) {
+	case 0:
+		ptemp[0] = clamp_val(val / 1000, 0,
+				     data->temp1_auto_point_temp[1]);
+		ptemp[0] = clamp_val(ptemp[0], 0,
+				     data->temp2_auto_point_temp[1]);
+		ptemp[0] = clamp_val(ptemp[0], 0, 63);
+		if (i2c_smbus_write_byte_data(
+					client,
+					AMC6821_REG_PSV_TEMP,
+					ptemp[0])) {
+				dev_err(&client->dev,
+					"Register write error, aborting.\n");
+				count = -EIO;
+		}
+		goto EXIT;
+	case 1:
+		ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
+		ptemp[1] &= 0x7C;
+		ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
+		break;
+	case 2:
+		ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
+		count = -EINVAL;
+		goto EXIT;
+	}
+	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
+	if (set_slope_register(client, reg, dpwm, ptemp))
+		count = -EIO;
+
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_pwm1_auto_point_pwm(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int dpwm;
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP,
+			data->pwm1_auto_point_pwm[1])) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+		goto EXIT;
+	}
+	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
+	if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm,
+			data->temp1_auto_point_temp)) {
+		count = -EIO;
+		goto EXIT;
+	}
+	if (set_slope_register(client, AMC6821_REG_RTEMP_FAN_CTRL, dpwm,
+			data->temp2_auto_point_temp)) {
+		count = -EIO;
+		goto EXIT;
+	}
+
+EXIT:
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_fan(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+	if (0 == data->fan[ix])
+		return sprintf(buf, "0");
+	return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix]));
+}
+
+static ssize_t get_fan1_fault(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	if (data->stat1 & AMC6821_STAT1_FANS)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+static ssize_t set_fan(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int ix = to_sensor_dev_attr(attr)->index;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = 1 > val ? 0xFFFF : 6000000/val;
+
+	mutex_lock(&data->update_lock);
+	data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF);
+	if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
+			data->fan[ix] & 0xFF)) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+		goto EXIT;
+	}
+	if (i2c_smbus_write_byte_data(client,
+			fan_reg_hi[ix], data->fan[ix] >> 8)) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+	}
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_fan1_div(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->fan1_div);
+}
+
+static ssize_t set_fan1_div(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct amc6821_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int config = kstrtol(buf, 10, &val);
+	if (config)
+		return config;
+
+	mutex_lock(&data->update_lock);
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+	if (config < 0) {
+		dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+		count = config;
+		goto EXIT;
+	}
+	switch (val) {
+	case 2:
+		config &= ~AMC6821_CONF4_PSPR;
+		data->fan1_div = 2;
+		break;
+	case 4:
+		config |= AMC6821_CONF4_PSPR;
+		data->fan1_div = 4;
+		break;
+	default:
+		count = -EINVAL;
+		goto EXIT;
+	}
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) {
+		dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+		count = -EIO;
+	}
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+	get_temp, NULL, IDX_TEMP1_INPUT);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_MIN);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_CRIT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP1_MIN);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP1_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP1_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
+	get_temp, NULL, IDX_TEMP2_INPUT);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_MIN);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_MAX);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO,
+	get_temp2_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP2_MIN);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP2_MAX);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP2_CRIT);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, IDX_FAN1_INPUT);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+	get_fan, set_fan, IDX_FAN1_MIN);
+static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR,
+	get_fan, set_fan, IDX_FAN1_MAX);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+	get_fan1_div, set_fan1_div, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm1, set_pwm1, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+	get_pwm1_enable, set_pwm1_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO,
+	get_pwm1_auto_point_pwm, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+	get_pwm1_auto_point_pwm, set_pwm1_auto_point_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO,
+	get_pwm1_auto_point_pwm, NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
+	get_pwm1_auto_channels_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO,
+	get_temp_auto_point_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point3_temp, S_IWUSR | S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point3_temp, S_IWUSR | S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 2);
+
+static struct attribute *amc6821_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point3_temp.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(amc6821);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int amc6821_detect(
+		struct i2c_client *client,
+		struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	int dev_id, comp_id;
+
+	dev_dbg(&adapter->dev, "amc6821_detect called.\n");
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_dbg(&adapter->dev,
+			"amc6821: I2C bus doesn't support byte mode, "
+			"skipping.\n");
+		return -ENODEV;
+	}
+
+	dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID);
+	comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID);
+	if (dev_id != 0x21 || comp_id != 0x49) {
+		dev_dbg(&adapter->dev,
+			"amc6821: detection failed at 0x%02x.\n",
+			address);
+		return -ENODEV;
+	}
+
+	/*
+	 * Bit 7 of the address register is ignored, so we can check the
+	 * ID registers again
+	 */
+	dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID);
+	comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID);
+	if (dev_id != 0x21 || comp_id != 0x49) {
+		dev_dbg(&adapter->dev,
+			"amc6821: detection failed at 0x%02x.\n",
+			address);
+		return -ENODEV;
+	}
+
+	dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address);
+	strlcpy(info->type, "amc6821", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int amc6821_init_client(struct i2c_client *client)
+{
+	int config;
+	int err = -EIO;
+
+	if (init) {
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+
+		if (config < 0) {
+				dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+				return err;
+		}
+
+		config |= AMC6821_CONF4_MODE;
+
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4,
+				config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF3);
+
+		if (config < 0) {
+			dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		dev_info(&client->dev, "Revision %d\n", config & 0x0f);
+
+		config &= ~AMC6821_CONF3_THERM_FAN_EN;
+
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF3,
+				config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF2);
+
+		if (config < 0) {
+			dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		config &= ~AMC6821_CONF2_RTFIE;
+		config &= ~AMC6821_CONF2_LTOIE;
+		config &= ~AMC6821_CONF2_RTOIE;
+		if (i2c_smbus_write_byte_data(client,
+				AMC6821_REG_CONF2, config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+
+		if (config < 0) {
+			dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		config &= ~AMC6821_CONF1_THERMOVIE;
+		config &= ~AMC6821_CONF1_FANIE;
+		config |= AMC6821_CONF1_START;
+		if (pwminv)
+			config |= AMC6821_CONF1_PWMINV;
+		else
+			config &= ~AMC6821_CONF1_PWMINV;
+
+		if (i2c_smbus_write_byte_data(
+				client, AMC6821_REG_CONF1, config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			return err;
+		}
+	}
+	return 0;
+}
+
+static int amc6821_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct amc6821_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the amc6821 chip
+	 */
+	err = amc6821_init_client(client);
+	if (err)
+		return err;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   amc6821_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id amc6821_id[] = {
+	{ "amc6821", amc6821 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, amc6821_id);
+
+static struct i2c_driver amc6821_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "amc6821",
+	},
+	.probe = amc6821_probe,
+	.id_table = amc6821_id,
+	.detect = amc6821_detect,
+	.address_list = normal_i2c,
+};
+
+module_i2c_driver(amc6821_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>");
+MODULE_DESCRIPTION("Texas Instruments amc6821 hwmon driver");
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
new file mode 100644
index 0000000..0af7fd3
--- /dev/null
+++ b/drivers/hwmon/applesmc.c
@@ -0,0 +1,1383 @@
+/*
+ * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
+ * sensors, fan control, keyboard backlight control) used in Intel-based Apple
+ * computers.
+ *
+ * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
+ *
+ * Based on hdaps.c driver:
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jj@chaosbits.net>
+ *
+ * Fan control based on smcFanControl:
+ * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * 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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/hwmon.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+
+/* data port used by Apple SMC */
+#define APPLESMC_DATA_PORT	0x300
+/* command/status port used by Apple SMC */
+#define APPLESMC_CMD_PORT	0x304
+
+#define APPLESMC_NR_PORTS	32 /* 0x300-0x31f */
+
+#define APPLESMC_MAX_DATA_LENGTH 32
+
+/* wait up to 128 ms for a status change. */
+#define APPLESMC_MIN_WAIT	0x0010
+#define APPLESMC_RETRY_WAIT	0x0100
+#define APPLESMC_MAX_WAIT	0x20000
+
+#define APPLESMC_READ_CMD	0x10
+#define APPLESMC_WRITE_CMD	0x11
+#define APPLESMC_GET_KEY_BY_INDEX_CMD	0x12
+#define APPLESMC_GET_KEY_TYPE_CMD	0x13
+
+#define KEY_COUNT_KEY		"#KEY" /* r-o ui32 */
+
+#define LIGHT_SENSOR_LEFT_KEY	"ALV0" /* r-o {alv (6-10 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY	"ALV1" /* r-o {alv (6-10 bytes) */
+#define BACKLIGHT_KEY		"LKSB" /* w-o {lkb (2 bytes) */
+
+#define CLAMSHELL_KEY		"MSLD" /* r-o ui8 (unused) */
+
+#define MOTION_SENSOR_X_KEY	"MO_X" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Y_KEY	"MO_Y" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Z_KEY	"MO_Z" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_KEY	"MOCN" /* r/w ui16 */
+
+#define FANS_COUNT		"FNum" /* r-o ui8 */
+#define FANS_MANUAL		"FS! " /* r-w ui16 */
+#define FAN_ID_FMT		"F%dID" /* r-o char[16] */
+
+#define TEMP_SENSOR_TYPE	"sp78"
+
+/* List of keys used to read/write fan speeds */
+static const char *const fan_speed_fmt[] = {
+	"F%dAc",		/* actual speed */
+	"F%dMn",		/* minimum speed (rw) */
+	"F%dMx",		/* maximum speed */
+	"F%dSf",		/* safe speed - not all models */
+	"F%dTg",		/* target speed (manual: rw) */
+};
+
+#define INIT_TIMEOUT_MSECS	5000	/* wait up to 5s for device init ... */
+#define INIT_WAIT_MSECS		50	/* ... in 50ms increments */
+
+#define APPLESMC_POLL_INTERVAL	50	/* msecs */
+#define APPLESMC_INPUT_FUZZ	4	/* input event threshold */
+#define APPLESMC_INPUT_FLAT	4
+
+#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
+#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
+
+/* Dynamic device node attributes */
+struct applesmc_dev_attr {
+	struct sensor_device_attribute sda;	/* hwmon attributes */
+	char name[32];				/* room for node file name */
+};
+
+/* Dynamic device node group */
+struct applesmc_node_group {
+	char *format;				/* format string */
+	void *show;				/* show function */
+	void *store;				/* store function */
+	int option;				/* function argument */
+	struct applesmc_dev_attr *nodes;	/* dynamic node array */
+};
+
+/* AppleSMC entry - cached register information */
+struct applesmc_entry {
+	char key[5];		/* four-letter key code */
+	u8 valid;		/* set when entry is successfully read once */
+	u8 len;			/* bounded by APPLESMC_MAX_DATA_LENGTH */
+	char type[5];		/* four-letter type code */
+	u8 flags;		/* 0x10: func; 0x40: write; 0x80: read */
+};
+
+/* Register lookup and registers common to all SMCs */
+static struct applesmc_registers {
+	struct mutex mutex;		/* register read/write mutex */
+	unsigned int key_count;		/* number of SMC registers */
+	unsigned int fan_count;		/* number of fans */
+	unsigned int temp_count;	/* number of temperature registers */
+	unsigned int temp_begin;	/* temperature lower index bound */
+	unsigned int temp_end;		/* temperature upper index bound */
+	unsigned int index_count;	/* size of temperature index array */
+	int num_light_sensors;		/* number of light sensors */
+	bool has_accelerometer;		/* has motion sensor */
+	bool has_key_backlight;		/* has keyboard backlight */
+	bool init_complete;		/* true when fully initialized */
+	struct applesmc_entry *cache;	/* cached key entries */
+	const char **index;		/* temperature key index */
+} smcreg = {
+	.mutex = __MUTEX_INITIALIZER(smcreg.mutex),
+};
+
+static const int debug;
+static struct platform_device *pdev;
+static s16 rest_x;
+static s16 rest_y;
+static u8 backlight_state[2];
+
+static struct device *hwmon_dev;
+static struct input_polled_dev *applesmc_idev;
+
+/*
+ * Last index written to key_at_index sysfs file, and value to use for all other
+ * key_at_index_* sysfs files.
+ */
+static unsigned int key_at_index;
+
+static struct workqueue_struct *applesmc_led_wq;
+
+/*
+ * wait_read - Wait for a byte to appear on SMC port. Callers must
+ * hold applesmc_lock.
+ */
+static int wait_read(void)
+{
+	u8 status;
+	int us;
+	for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+		udelay(us);
+		status = inb(APPLESMC_CMD_PORT);
+		/* read: wait for smc to settle */
+		if (status & 0x01)
+			return 0;
+	}
+
+	pr_warn("wait_read() fail: 0x%02x\n", status);
+	return -EIO;
+}
+
+/*
+ * send_byte - Write to SMC port, retrying when necessary. Callers
+ * must hold applesmc_lock.
+ */
+static int send_byte(u8 cmd, u16 port)
+{
+	u8 status;
+	int us;
+
+	outb(cmd, port);
+	for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+		udelay(us);
+		status = inb(APPLESMC_CMD_PORT);
+		/* write: wait for smc to settle */
+		if (status & 0x02)
+			continue;
+		/* ready: cmd accepted, return */
+		if (status & 0x04)
+			return 0;
+		/* timeout: give up */
+		if (us << 1 == APPLESMC_MAX_WAIT)
+			break;
+		/* busy: long wait and resend */
+		udelay(APPLESMC_RETRY_WAIT);
+		outb(cmd, port);
+	}
+
+	pr_warn("send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status);
+	return -EIO;
+}
+
+static int send_command(u8 cmd)
+{
+	return send_byte(cmd, APPLESMC_CMD_PORT);
+}
+
+static int send_argument(const char *key)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		if (send_byte(key[i], APPLESMC_DATA_PORT))
+			return -EIO;
+	return 0;
+}
+
+static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
+{
+	u8 status, data = 0;
+	int i;
+
+	if (send_command(cmd) || send_argument(key)) {
+		pr_warn("%.4s: read arg fail\n", key);
+		return -EIO;
+	}
+
+	/* This has no effect on newer (2012) SMCs */
+	if (send_byte(len, APPLESMC_DATA_PORT)) {
+		pr_warn("%.4s: read len fail\n", key);
+		return -EIO;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (wait_read()) {
+			pr_warn("%.4s: read data[%d] fail\n", key, i);
+			return -EIO;
+		}
+		buffer[i] = inb(APPLESMC_DATA_PORT);
+	}
+
+	/* Read the data port until bit0 is cleared */
+	for (i = 0; i < 16; i++) {
+		udelay(APPLESMC_MIN_WAIT);
+		status = inb(APPLESMC_CMD_PORT);
+		if (!(status & 0x01))
+			break;
+		data = inb(APPLESMC_DATA_PORT);
+	}
+	if (i)
+		pr_warn("flushed %d bytes, last value is: %d\n", i, data);
+
+	return 0;
+}
+
+static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
+{
+	int i;
+
+	if (send_command(cmd) || send_argument(key)) {
+		pr_warn("%s: write arg fail\n", key);
+		return -EIO;
+	}
+
+	if (send_byte(len, APPLESMC_DATA_PORT)) {
+		pr_warn("%.4s: write len fail\n", key);
+		return -EIO;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
+			pr_warn("%s: write data fail\n", key);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int read_register_count(unsigned int *count)
+{
+	__be32 be;
+	int ret;
+
+	ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
+	if (ret)
+		return ret;
+
+	*count = be32_to_cpu(be);
+	return 0;
+}
+
+/*
+ * Serialized I/O
+ *
+ * Returns zero on success or a negative error on failure.
+ * All functions below are concurrency safe - callers should NOT hold lock.
+ */
+
+static int applesmc_read_entry(const struct applesmc_entry *entry,
+			       u8 *buf, u8 len)
+{
+	int ret;
+
+	if (entry->len != len)
+		return -EINVAL;
+	mutex_lock(&smcreg.mutex);
+	ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
+	mutex_unlock(&smcreg.mutex);
+
+	return ret;
+}
+
+static int applesmc_write_entry(const struct applesmc_entry *entry,
+				const u8 *buf, u8 len)
+{
+	int ret;
+
+	if (entry->len != len)
+		return -EINVAL;
+	mutex_lock(&smcreg.mutex);
+	ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
+	mutex_unlock(&smcreg.mutex);
+	return ret;
+}
+
+static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
+{
+	struct applesmc_entry *cache = &smcreg.cache[index];
+	u8 key[4], info[6];
+	__be32 be;
+	int ret = 0;
+
+	if (cache->valid)
+		return cache;
+
+	mutex_lock(&smcreg.mutex);
+
+	if (cache->valid)
+		goto out;
+	be = cpu_to_be32(index);
+	ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
+	if (ret)
+		goto out;
+	ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
+	if (ret)
+		goto out;
+
+	memcpy(cache->key, key, 4);
+	cache->len = info[0];
+	memcpy(cache->type, &info[1], 4);
+	cache->flags = info[5];
+	cache->valid = 1;
+
+out:
+	mutex_unlock(&smcreg.mutex);
+	if (ret)
+		return ERR_PTR(ret);
+	return cache;
+}
+
+static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
+{
+	int begin = 0, end = smcreg.key_count;
+	const struct applesmc_entry *entry;
+
+	while (begin != end) {
+		int middle = begin + (end - begin) / 2;
+		entry = applesmc_get_entry_by_index(middle);
+		if (IS_ERR(entry)) {
+			*lo = 0;
+			return PTR_ERR(entry);
+		}
+		if (strcmp(entry->key, key) < 0)
+			begin = middle + 1;
+		else
+			end = middle;
+	}
+
+	*lo = begin;
+	return 0;
+}
+
+static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
+{
+	int begin = 0, end = smcreg.key_count;
+	const struct applesmc_entry *entry;
+
+	while (begin != end) {
+		int middle = begin + (end - begin) / 2;
+		entry = applesmc_get_entry_by_index(middle);
+		if (IS_ERR(entry)) {
+			*hi = smcreg.key_count;
+			return PTR_ERR(entry);
+		}
+		if (strcmp(key, entry->key) < 0)
+			end = middle;
+		else
+			begin = middle + 1;
+	}
+
+	*hi = begin;
+	return 0;
+}
+
+static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
+{
+	int begin, end;
+	int ret;
+
+	ret = applesmc_get_lower_bound(&begin, key);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = applesmc_get_upper_bound(&end, key);
+	if (ret)
+		return ERR_PTR(ret);
+	if (end - begin != 1)
+		return ERR_PTR(-EINVAL);
+
+	return applesmc_get_entry_by_index(begin);
+}
+
+static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_key(key);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+
+	return applesmc_read_entry(entry, buffer, len);
+}
+
+static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_key(key);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+
+	return applesmc_write_entry(entry, buffer, len);
+}
+
+static int applesmc_has_key(const char *key, bool *value)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_key(key);
+	if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
+		return PTR_ERR(entry);
+
+	*value = !IS_ERR(entry);
+	return 0;
+}
+
+/*
+ * applesmc_read_s16 - Read 16-bit signed big endian register
+ */
+static int applesmc_read_s16(const char *key, s16 *value)
+{
+	u8 buffer[2];
+	int ret;
+
+	ret = applesmc_read_key(key, buffer, 2);
+	if (ret)
+		return ret;
+
+	*value = ((s16)buffer[0] << 8) | buffer[1];
+	return 0;
+}
+
+/*
+ * applesmc_device_init - initialize the accelerometer.  Can sleep.
+ */
+static void applesmc_device_init(void)
+{
+	int total;
+	u8 buffer[2];
+
+	if (!smcreg.has_accelerometer)
+		return;
+
+	for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+		if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
+				(buffer[0] != 0x00 || buffer[1] != 0x00))
+			return;
+		buffer[0] = 0xe0;
+		buffer[1] = 0x00;
+		applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
+		msleep(INIT_WAIT_MSECS);
+	}
+
+	pr_warn("failed to init the device\n");
+}
+
+static int applesmc_init_index(struct applesmc_registers *s)
+{
+	const struct applesmc_entry *entry;
+	unsigned int i;
+
+	if (s->index)
+		return 0;
+
+	s->index = kcalloc(s->temp_count, sizeof(s->index[0]), GFP_KERNEL);
+	if (!s->index)
+		return -ENOMEM;
+
+	for (i = s->temp_begin; i < s->temp_end; i++) {
+		entry = applesmc_get_entry_by_index(i);
+		if (IS_ERR(entry))
+			continue;
+		if (strcmp(entry->type, TEMP_SENSOR_TYPE))
+			continue;
+		s->index[s->index_count++] = entry->key;
+	}
+
+	return 0;
+}
+
+/*
+ * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
+ */
+static int applesmc_init_smcreg_try(void)
+{
+	struct applesmc_registers *s = &smcreg;
+	bool left_light_sensor = 0, right_light_sensor = 0;
+	unsigned int count;
+	u8 tmp[1];
+	int ret;
+
+	if (s->init_complete)
+		return 0;
+
+	ret = read_register_count(&count);
+	if (ret)
+		return ret;
+
+	if (s->cache && s->key_count != count) {
+		pr_warn("key count changed from %d to %d\n",
+			s->key_count, count);
+		kfree(s->cache);
+		s->cache = NULL;
+	}
+	s->key_count = count;
+
+	if (!s->cache)
+		s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
+	if (!s->cache)
+		return -ENOMEM;
+
+	ret = applesmc_read_key(FANS_COUNT, tmp, 1);
+	if (ret)
+		return ret;
+	s->fan_count = tmp[0];
+
+	ret = applesmc_get_lower_bound(&s->temp_begin, "T");
+	if (ret)
+		return ret;
+	ret = applesmc_get_lower_bound(&s->temp_end, "U");
+	if (ret)
+		return ret;
+	s->temp_count = s->temp_end - s->temp_begin;
+
+	ret = applesmc_init_index(s);
+	if (ret)
+		return ret;
+
+	ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
+	if (ret)
+		return ret;
+	ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
+	if (ret)
+		return ret;
+	ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
+	if (ret)
+		return ret;
+	ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
+	if (ret)
+		return ret;
+
+	s->num_light_sensors = left_light_sensor + right_light_sensor;
+	s->init_complete = true;
+
+	pr_info("key=%d fan=%d temp=%d index=%d acc=%d lux=%d kbd=%d\n",
+	       s->key_count, s->fan_count, s->temp_count, s->index_count,
+	       s->has_accelerometer,
+	       s->num_light_sensors,
+	       s->has_key_backlight);
+
+	return 0;
+}
+
+static void applesmc_destroy_smcreg(void)
+{
+	kfree(smcreg.index);
+	smcreg.index = NULL;
+	kfree(smcreg.cache);
+	smcreg.cache = NULL;
+	smcreg.init_complete = false;
+}
+
+/*
+ * applesmc_init_smcreg - Initialize register cache.
+ *
+ * Retries until initialization is successful, or the operation times out.
+ *
+ */
+static int applesmc_init_smcreg(void)
+{
+	int ms, ret;
+
+	for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
+		ret = applesmc_init_smcreg_try();
+		if (!ret) {
+			if (ms)
+				pr_info("init_smcreg() took %d ms\n", ms);
+			return 0;
+		}
+		msleep(INIT_WAIT_MSECS);
+	}
+
+	applesmc_destroy_smcreg();
+
+	return ret;
+}
+
+/* Device model stuff */
+static int applesmc_probe(struct platform_device *dev)
+{
+	int ret;
+
+	ret = applesmc_init_smcreg();
+	if (ret)
+		return ret;
+
+	applesmc_device_init();
+
+	return 0;
+}
+
+/* Synchronize device with memorized backlight state */
+static int applesmc_pm_resume(struct device *dev)
+{
+	if (smcreg.has_key_backlight)
+		applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
+	return 0;
+}
+
+/* Reinitialize device on resume from hibernation */
+static int applesmc_pm_restore(struct device *dev)
+{
+	applesmc_device_init();
+	return applesmc_pm_resume(dev);
+}
+
+static const struct dev_pm_ops applesmc_pm_ops = {
+	.resume = applesmc_pm_resume,
+	.restore = applesmc_pm_restore,
+};
+
+static struct platform_driver applesmc_driver = {
+	.probe = applesmc_probe,
+	.driver	= {
+		.name = "applesmc",
+		.pm = &applesmc_pm_ops,
+	},
+};
+
+/*
+ * applesmc_calibrate - Set our "resting" values.  Callers must
+ * hold applesmc_lock.
+ */
+static void applesmc_calibrate(void)
+{
+	applesmc_read_s16(MOTION_SENSOR_X_KEY, &rest_x);
+	applesmc_read_s16(MOTION_SENSOR_Y_KEY, &rest_y);
+	rest_x = -rest_x;
+}
+
+static void applesmc_idev_poll(struct input_polled_dev *dev)
+{
+	struct input_dev *idev = dev->input;
+	s16 x, y;
+
+	if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
+		return;
+	if (applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y))
+		return;
+
+	x = -x;
+	input_report_abs(idev, ABS_X, x - rest_x);
+	input_report_abs(idev, ABS_Y, y - rest_y);
+	input_sync(idev);
+}
+
+/* Sysfs Files */
+
+static ssize_t applesmc_name_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "applesmc\n");
+}
+
+static ssize_t applesmc_position_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	int ret;
+	s16 x, y, z;
+
+	ret = applesmc_read_s16(MOTION_SENSOR_X_KEY, &x);
+	if (ret)
+		goto out;
+	ret = applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y);
+	if (ret)
+		goto out;
+	ret = applesmc_read_s16(MOTION_SENSOR_Z_KEY, &z);
+	if (ret)
+		goto out;
+
+out:
+	if (ret)
+		return ret;
+	else
+		return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t applesmc_light_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	const struct applesmc_entry *entry;
+	static int data_length;
+	int ret;
+	u8 left = 0, right = 0;
+	u8 buffer[10];
+
+	if (!data_length) {
+		entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
+		if (entry->len > 10)
+			return -ENXIO;
+		data_length = entry->len;
+		pr_info("light sensor data length set to %d\n", data_length);
+	}
+
+	ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+	/* newer macbooks report a single 10-bit bigendian value */
+	if (data_length == 10) {
+		left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
+		goto out;
+	}
+	left = buffer[2];
+	if (ret)
+		goto out;
+	ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
+	right = buffer[2];
+
+out:
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
+}
+
+/* Displays sensor key as label */
+static ssize_t applesmc_show_sensor_label(struct device *dev,
+			struct device_attribute *devattr, char *sysfsbuf)
+{
+	const char *key = smcreg.index[to_index(devattr)];
+
+	return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+}
+
+/* Displays degree Celsius * 1000 */
+static ssize_t applesmc_show_temperature(struct device *dev,
+			struct device_attribute *devattr, char *sysfsbuf)
+{
+	const char *key = smcreg.index[to_index(devattr)];
+	int ret;
+	s16 value;
+	int temp;
+
+	ret = applesmc_read_s16(key, &value);
+	if (ret)
+		return ret;
+
+	temp = 250 * (value >> 6);
+
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t applesmc_show_fan_speed(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	unsigned int speed = 0;
+	char newkey[5];
+	u8 buffer[2];
+
+	sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
+
+	ret = applesmc_read_key(newkey, buffer, 2);
+	speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+}
+
+static ssize_t applesmc_store_fan_speed(struct device *dev,
+					struct device_attribute *attr,
+					const char *sysfsbuf, size_t count)
+{
+	int ret;
+	unsigned long speed;
+	char newkey[5];
+	u8 buffer[2];
+
+	if (kstrtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
+		return -EINVAL;		/* Bigger than a 14-bit value */
+
+	sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
+
+	buffer[0] = (speed >> 6) & 0xff;
+	buffer[1] = (speed << 2) & 0xff;
+	ret = applesmc_write_key(newkey, buffer, 2);
+
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static ssize_t applesmc_show_fan_manual(struct device *dev,
+			struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	u16 manual = 0;
+	u8 buffer[2];
+
+	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+	manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+}
+
+static ssize_t applesmc_store_fan_manual(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *sysfsbuf, size_t count)
+{
+	int ret;
+	u8 buffer[2];
+	unsigned long input;
+	u16 val;
+
+	if (kstrtoul(sysfsbuf, 10, &input) < 0)
+		return -EINVAL;
+
+	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+	val = (buffer[0] << 8 | buffer[1]);
+	if (ret)
+		goto out;
+
+	if (input)
+		val = val | (0x01 << to_index(attr));
+	else
+		val = val & ~(0x01 << to_index(attr));
+
+	buffer[0] = (val >> 8) & 0xFF;
+	buffer[1] = val & 0xFF;
+
+	ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
+
+out:
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static ssize_t applesmc_show_fan_position(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	char newkey[5];
+	u8 buffer[17];
+
+	sprintf(newkey, FAN_ID_FMT, to_index(attr));
+
+	ret = applesmc_read_key(newkey, buffer, 16);
+	buffer[16] = 0;
+
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
+}
+
+static ssize_t applesmc_calibrate_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t applesmc_calibrate_store(struct device *dev,
+	struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+	applesmc_calibrate();
+
+	return count;
+}
+
+static void applesmc_backlight_set(struct work_struct *work)
+{
+	applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
+}
+static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
+
+static void applesmc_brightness_set(struct led_classdev *led_cdev,
+						enum led_brightness value)
+{
+	int ret;
+
+	backlight_state[0] = value;
+	ret = queue_work(applesmc_led_wq, &backlight_work);
+
+	if (debug && (!ret))
+		dev_dbg(led_cdev->dev, "work was already on the queue.\n");
+}
+
+static ssize_t applesmc_key_count_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	u8 buffer[4];
+	u32 count;
+
+	ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
+	count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
+						((u32)buffer[2]<<8) + buffer[3];
+
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+}
+
+static ssize_t applesmc_key_at_index_read_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	const struct applesmc_entry *entry;
+	int ret;
+
+	entry = applesmc_get_entry_by_index(key_at_index);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+	ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
+	if (ret)
+		return ret;
+
+	return entry->len;
+}
+
+static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_index(key_at_index);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
+}
+
+static ssize_t applesmc_key_at_index_type_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_index(key_at_index);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+
+	return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
+}
+
+static ssize_t applesmc_key_at_index_name_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	const struct applesmc_entry *entry;
+
+	entry = applesmc_get_entry_by_index(key_at_index);
+	if (IS_ERR(entry))
+		return PTR_ERR(entry);
+
+	return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
+}
+
+static ssize_t applesmc_key_at_index_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
+}
+
+static ssize_t applesmc_key_at_index_store(struct device *dev,
+	struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+	unsigned long newkey;
+
+	if (kstrtoul(sysfsbuf, 10, &newkey) < 0
+	    || newkey >= smcreg.key_count)
+		return -EINVAL;
+
+	key_at_index = newkey;
+	return count;
+}
+
+static struct led_classdev applesmc_backlight = {
+	.name			= "smc::kbd_backlight",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= applesmc_brightness_set,
+};
+
+static struct applesmc_node_group info_group[] = {
+	{ "name", applesmc_name_show },
+	{ "key_count", applesmc_key_count_show },
+	{ "key_at_index", applesmc_key_at_index_show, applesmc_key_at_index_store },
+	{ "key_at_index_name", applesmc_key_at_index_name_show },
+	{ "key_at_index_type", applesmc_key_at_index_type_show },
+	{ "key_at_index_data_length", applesmc_key_at_index_data_length_show },
+	{ "key_at_index_data", applesmc_key_at_index_read_show },
+	{ }
+};
+
+static struct applesmc_node_group accelerometer_group[] = {
+	{ "position", applesmc_position_show },
+	{ "calibrate", applesmc_calibrate_show, applesmc_calibrate_store },
+	{ }
+};
+
+static struct applesmc_node_group light_sensor_group[] = {
+	{ "light", applesmc_light_show },
+	{ }
+};
+
+static struct applesmc_node_group fan_group[] = {
+	{ "fan%d_label", applesmc_show_fan_position },
+	{ "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
+	{ "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
+	{ "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
+	{ "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
+	{ "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
+	{ "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
+	{ }
+};
+
+static struct applesmc_node_group temp_group[] = {
+	{ "temp%d_label", applesmc_show_sensor_label },
+	{ "temp%d_input", applesmc_show_temperature },
+	{ }
+};
+
+/* Module stuff */
+
+/*
+ * applesmc_destroy_nodes - remove files and free associated memory
+ */
+static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
+{
+	struct applesmc_node_group *grp;
+	struct applesmc_dev_attr *node;
+
+	for (grp = groups; grp->nodes; grp++) {
+		for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
+			sysfs_remove_file(&pdev->dev.kobj,
+					  &node->sda.dev_attr.attr);
+		kfree(grp->nodes);
+		grp->nodes = NULL;
+	}
+}
+
+/*
+ * applesmc_create_nodes - create a two-dimensional group of sysfs files
+ */
+static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
+{
+	struct applesmc_node_group *grp;
+	struct applesmc_dev_attr *node;
+	struct attribute *attr;
+	int ret, i;
+
+	for (grp = groups; grp->format; grp++) {
+		grp->nodes = kcalloc(num + 1, sizeof(*node), GFP_KERNEL);
+		if (!grp->nodes) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		for (i = 0; i < num; i++) {
+			node = &grp->nodes[i];
+			sprintf(node->name, grp->format, i + 1);
+			node->sda.index = (grp->option << 16) | (i & 0xffff);
+			node->sda.dev_attr.show = grp->show;
+			node->sda.dev_attr.store = grp->store;
+			attr = &node->sda.dev_attr.attr;
+			sysfs_attr_init(attr);
+			attr->name = node->name;
+			attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
+			ret = sysfs_create_file(&pdev->dev.kobj, attr);
+			if (ret) {
+				attr->name = NULL;
+				goto out;
+			}
+		}
+	}
+
+	return 0;
+out:
+	applesmc_destroy_nodes(groups);
+	return ret;
+}
+
+/* Create accelerometer resources */
+static int applesmc_create_accelerometer(void)
+{
+	struct input_dev *idev;
+	int ret;
+
+	if (!smcreg.has_accelerometer)
+		return 0;
+
+	ret = applesmc_create_nodes(accelerometer_group, 1);
+	if (ret)
+		goto out;
+
+	applesmc_idev = input_allocate_polled_device();
+	if (!applesmc_idev) {
+		ret = -ENOMEM;
+		goto out_sysfs;
+	}
+
+	applesmc_idev->poll = applesmc_idev_poll;
+	applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
+
+	/* initial calibrate for the input device */
+	applesmc_calibrate();
+
+	/* initialize the input device */
+	idev = applesmc_idev->input;
+	idev->name = "applesmc";
+	idev->id.bustype = BUS_HOST;
+	idev->dev.parent = &pdev->dev;
+	idev->evbit[0] = BIT_MASK(EV_ABS);
+	input_set_abs_params(idev, ABS_X,
+			-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+	input_set_abs_params(idev, ABS_Y,
+			-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+
+	ret = input_register_polled_device(applesmc_idev);
+	if (ret)
+		goto out_idev;
+
+	return 0;
+
+out_idev:
+	input_free_polled_device(applesmc_idev);
+
+out_sysfs:
+	applesmc_destroy_nodes(accelerometer_group);
+
+out:
+	pr_warn("driver init failed (ret=%d)!\n", ret);
+	return ret;
+}
+
+/* Release all resources used by the accelerometer */
+static void applesmc_release_accelerometer(void)
+{
+	if (!smcreg.has_accelerometer)
+		return;
+	input_unregister_polled_device(applesmc_idev);
+	input_free_polled_device(applesmc_idev);
+	applesmc_destroy_nodes(accelerometer_group);
+}
+
+static int applesmc_create_light_sensor(void)
+{
+	if (!smcreg.num_light_sensors)
+		return 0;
+	return applesmc_create_nodes(light_sensor_group, 1);
+}
+
+static void applesmc_release_light_sensor(void)
+{
+	if (!smcreg.num_light_sensors)
+		return;
+	applesmc_destroy_nodes(light_sensor_group);
+}
+
+static int applesmc_create_key_backlight(void)
+{
+	if (!smcreg.has_key_backlight)
+		return 0;
+	applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+	if (!applesmc_led_wq)
+		return -ENOMEM;
+	return led_classdev_register(&pdev->dev, &applesmc_backlight);
+}
+
+static void applesmc_release_key_backlight(void)
+{
+	if (!smcreg.has_key_backlight)
+		return;
+	led_classdev_unregister(&applesmc_backlight);
+	destroy_workqueue(applesmc_led_wq);
+}
+
+static int applesmc_dmi_match(const struct dmi_system_id *id)
+{
+	return 1;
+}
+
+/*
+ * Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
+ * So we need to put "Apple MacBook Pro" before "Apple MacBook".
+ */
+static __initdata struct dmi_system_id applesmc_whitelist[] = {
+	{ applesmc_dmi_match, "Apple MacBook Air", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
+	},
+	{ applesmc_dmi_match, "Apple MacBook Pro", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro") },
+	},
+	{ applesmc_dmi_match, "Apple MacBook", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
+	},
+	{ applesmc_dmi_match, "Apple Macmini", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
+	},
+	{ applesmc_dmi_match, "Apple MacPro", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
+	},
+	{ applesmc_dmi_match, "Apple iMac", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "iMac") },
+	},
+	{ .ident = NULL }
+};
+
+static int __init applesmc_init(void)
+{
+	int ret;
+
+	if (!dmi_check_system(applesmc_whitelist)) {
+		pr_warn("supported laptop not found!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
+								"applesmc")) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = platform_driver_register(&applesmc_driver);
+	if (ret)
+		goto out_region;
+
+	pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
+					       NULL, 0);
+	if (IS_ERR(pdev)) {
+		ret = PTR_ERR(pdev);
+		goto out_driver;
+	}
+
+	/* create register cache */
+	ret = applesmc_init_smcreg();
+	if (ret)
+		goto out_device;
+
+	ret = applesmc_create_nodes(info_group, 1);
+	if (ret)
+		goto out_smcreg;
+
+	ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
+	if (ret)
+		goto out_info;
+
+	ret = applesmc_create_nodes(temp_group, smcreg.index_count);
+	if (ret)
+		goto out_fans;
+
+	ret = applesmc_create_accelerometer();
+	if (ret)
+		goto out_temperature;
+
+	ret = applesmc_create_light_sensor();
+	if (ret)
+		goto out_accelerometer;
+
+	ret = applesmc_create_key_backlight();
+	if (ret)
+		goto out_light_sysfs;
+
+	hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(hwmon_dev)) {
+		ret = PTR_ERR(hwmon_dev);
+		goto out_light_ledclass;
+	}
+
+	return 0;
+
+out_light_ledclass:
+	applesmc_release_key_backlight();
+out_light_sysfs:
+	applesmc_release_light_sensor();
+out_accelerometer:
+	applesmc_release_accelerometer();
+out_temperature:
+	applesmc_destroy_nodes(temp_group);
+out_fans:
+	applesmc_destroy_nodes(fan_group);
+out_info:
+	applesmc_destroy_nodes(info_group);
+out_smcreg:
+	applesmc_destroy_smcreg();
+out_device:
+	platform_device_unregister(pdev);
+out_driver:
+	platform_driver_unregister(&applesmc_driver);
+out_region:
+	release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+out:
+	pr_warn("driver init failed (ret=%d)!\n", ret);
+	return ret;
+}
+
+static void __exit applesmc_exit(void)
+{
+	hwmon_device_unregister(hwmon_dev);
+	applesmc_release_key_backlight();
+	applesmc_release_light_sensor();
+	applesmc_release_accelerometer();
+	applesmc_destroy_nodes(temp_group);
+	applesmc_destroy_nodes(fan_group);
+	applesmc_destroy_nodes(info_group);
+	applesmc_destroy_smcreg();
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&applesmc_driver);
+	release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+}
+
+module_init(applesmc_init);
+module_exit(applesmc_exit);
+
+MODULE_AUTHOR("Nicolas Boichat");
+MODULE_DESCRIPTION("Apple SMC");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
new file mode 100644
index 0000000..272fcc8
--- /dev/null
+++ b/drivers/hwmon/asb100.c
@@ -0,0 +1,1025 @@
+/*
+ * asb100.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	      monitoring
+ *
+ * Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+ *
+ * (derived from w83781d.c)
+ *
+ * Copyright (C) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *			      Philip Edelbrock <phil@netroedge.com>, and
+ *			      Mark Studebaker <mdsxyz123@yahoo.com>
+ *
+ * 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.
+ */
+
+/*
+ * This driver supports the hardware sensor chips: Asus ASB100 and
+ * ASB100-A "BACH".
+ *
+ * ASB100-A supports pwm1, while plain ASB100 does not.  There is no known
+ * way for the driver to tell which one is there.
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * asb100	7	3	1	4	0x31	0x0694	yes	no
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include "lm75.h"
+
+/* I2C addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients,
+	"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+/* Voltage IN registers 0-6 */
+#define ASB100_REG_IN(nr)	(0x20 + (nr))
+#define ASB100_REG_IN_MAX(nr)	(0x2b + (nr * 2))
+#define ASB100_REG_IN_MIN(nr)	(0x2c + (nr * 2))
+
+/* FAN IN registers 1-3 */
+#define ASB100_REG_FAN(nr)	(0x28 + (nr))
+#define ASB100_REG_FAN_MIN(nr)	(0x3b + (nr))
+
+/* TEMPERATURE registers 1-4 */
+static const u16 asb100_reg_temp[]	= {0, 0x27, 0x150, 0x250, 0x17};
+static const u16 asb100_reg_temp_max[]	= {0, 0x39, 0x155, 0x255, 0x18};
+static const u16 asb100_reg_temp_hyst[]	= {0, 0x3a, 0x153, 0x253, 0x19};
+
+#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr])
+#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr])
+#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr])
+
+#define ASB100_REG_TEMP2_CONFIG	0x0152
+#define ASB100_REG_TEMP3_CONFIG	0x0252
+
+
+#define ASB100_REG_CONFIG	0x40
+#define ASB100_REG_ALARM1	0x41
+#define ASB100_REG_ALARM2	0x42
+#define ASB100_REG_SMIM1	0x43
+#define ASB100_REG_SMIM2	0x44
+#define ASB100_REG_VID_FANDIV	0x47
+#define ASB100_REG_I2C_ADDR	0x48
+#define ASB100_REG_CHIPID	0x49
+#define ASB100_REG_I2C_SUBADDR	0x4a
+#define ASB100_REG_PIN		0x4b
+#define ASB100_REG_IRQ		0x4c
+#define ASB100_REG_BANK		0x4e
+#define ASB100_REG_CHIPMAN	0x4f
+
+#define ASB100_REG_WCHIPID	0x58
+
+/* bit 7 -> enable, bits 0-3 -> duty cycle */
+#define ASB100_REG_PWM1		0x59
+
+/*
+ * CONVERSIONS
+ * Rounding and limit checking is only done on the TO_REG variants.
+ */
+
+/* These constants are a guess, consistent w/ w83781d */
+#define ASB100_IN_MIN		0
+#define ASB100_IN_MAX		4080
+
+/*
+ * IN: 1/1000 V (0V to 4.08V)
+ * REG: 16mV/bit
+ */
+static u8 IN_TO_REG(unsigned val)
+{
+	unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
+	return (nval + 8) / 16;
+}
+
+static unsigned IN_FROM_REG(u8 reg)
+{
+	return reg * 16;
+}
+
+static u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == -1)
+		return 0;
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static int FAN_FROM_REG(u8 val, int div)
+{
+	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
+}
+
+/* These constants are a guess, consistent w/ w83781d */
+#define ASB100_TEMP_MIN		-128000
+#define ASB100_TEMP_MAX		127000
+
+/*
+ * TEMP: 0.001C/bit (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static u8 TEMP_TO_REG(long temp)
+{
+	int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
+}
+
+static int TEMP_FROM_REG(u8 reg)
+{
+	return (s8)reg * 1000;
+}
+
+/*
+ * PWM: 0 - 255 per sensors documentation
+ * REG: (6.25% duty cycle per bit)
+ */
+static u8 ASB100_PWM_TO_REG(int pwm)
+{
+	pwm = clamp_val(pwm, 0, 255);
+	return (u8)(pwm / 16);
+}
+
+static int ASB100_PWM_FROM_REG(u8 reg)
+{
+	return reg * 16;
+}
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+/*
+ * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
+ * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
+ */
+static u8 DIV_TO_REG(long val)
+{
+	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
+}
+
+/*
+ * For each registered client, we need to keep some data in memory. That
+ * data is pointed to by client->data. The structure itself is
+ * dynamically allocated, at the same time the client itself is allocated.
+ */
+struct asb100_data {
+	struct device *hwmon_dev;
+	struct mutex lock;
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+
+	/* array of 2 pointers to subclients */
+	struct i2c_client *lm75[2];
+
+	char valid;		/* !=0 if following fields are valid */
+	u8 in[7];		/* Register value */
+	u8 in_max[7];		/* Register value */
+	u8 in_min[7];		/* Register value */
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	u16 temp[4];		/* Register value (0 and 3 are u8 only) */
+	u16 temp_max[4];	/* Register value (0 and 3 are u8 only) */
+	u16 temp_hyst[4];	/* Register value (0 and 3 are u8 only) */
+	u8 fan_div[3];		/* Register encoding, right justified */
+	u8 pwm;			/* Register encoding */
+	u8 vid;			/* Register encoding, combined */
+	u32 alarms;		/* Register encoding, combined */
+	u8 vrm;
+};
+
+static int asb100_read_value(struct i2c_client *client, u16 reg);
+static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
+
+static int asb100_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
+static int asb100_detect(struct i2c_client *client,
+			 struct i2c_board_info *info);
+static int asb100_remove(struct i2c_client *client);
+static struct asb100_data *asb100_update_device(struct device *dev);
+static void asb100_init_client(struct i2c_client *client);
+
+static const struct i2c_device_id asb100_id[] = {
+	{ "asb100", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, asb100_id);
+
+static struct i2c_driver asb100_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "asb100",
+	},
+	.probe		= asb100_probe,
+	.remove		= asb100_remove,
+	.id_table	= asb100_id,
+	.detect		= asb100_detect,
+	.address_list	= normal_i2c,
+};
+
+/* 7 Voltages */
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+		char *buf) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct asb100_data *data = asb100_update_device(dev); \
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \
+}
+
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define set_in_reg(REG, reg) \
+static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \
+		const char *buf, size_t count) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct asb100_data *data = i2c_get_clientdata(client); \
+	unsigned long val; \
+	int err = kstrtoul(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = IN_TO_REG(val); \
+	asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
+		data->in_##reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+set_in_reg(MIN, min)
+set_in_reg(MAX, max)
+
+#define sysfs_in(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+		show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+		show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+		show_in_max, set_in_max, offset)
+
+sysfs_in(0);
+sysfs_in(1);
+sysfs_in(2);
+sysfs_in(3);
+sysfs_in(4);
+sysfs_in(5);
+sysfs_in(6);
+
+/* 3 Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asb100_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asb100_data *data = i2c_get_clientdata(client);
+	unsigned long min;
+	int reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	min = FAN_FROM_REG(data->fan_min[nr],
+			DIV_FROM_REG(data->fan_div[nr]));
+	data->fan_div[nr] = DIV_TO_REG(val);
+
+	switch (nr) {
+	case 0:	/* fan 1 */
+		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
+		reg = (reg & 0xcf) | (data->fan_div[0] << 4);
+		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
+		break;
+
+	case 1:	/* fan 2 */
+		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
+		reg = (reg & 0x3f) | (data->fan_div[1] << 6);
+		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
+		break;
+
+	case 2:	/* fan 3 */
+		reg = asb100_read_value(client, ASB100_REG_PIN);
+		reg = (reg & 0x3f) | (data->fan_div[2] << 6);
+		asb100_write_value(client, ASB100_REG_PIN, reg);
+		break;
+	}
+
+	data->fan_min[nr] =
+		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define sysfs_fan(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+		show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+		show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+		show_fan_div, set_fan_div, offset - 1)
+
+sysfs_fan(1);
+sysfs_fan(2);
+sysfs_fan(3);
+
+/* 4 Temp. Sensors */
+static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
+{
+	int ret = 0;
+
+	switch (nr) {
+	case 1: case 2:
+		ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg));
+		break;
+	case 0: case 3: default:
+		ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg));
+		break;
+	}
+	return ret;
+}
+
+#define show_temp_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+		char *buf) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct asb100_data *data = asb100_update_device(dev); \
+	return sprintf_temp_from_reg(data->reg[nr], buf, nr); \
+}
+
+show_temp_reg(temp);
+show_temp_reg(temp_max);
+show_temp_reg(temp_hyst);
+
+#define set_temp_reg(REG, reg) \
+static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \
+		const char *buf, size_t count) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct asb100_data *data = i2c_get_clientdata(client); \
+	long val; \
+	int err = kstrtol(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	switch (nr) { \
+	case 1: case 2: \
+		data->reg[nr] = LM75_TEMP_TO_REG(val); \
+		break; \
+	case 0: case 3: default: \
+		data->reg[nr] = TEMP_TO_REG(val); \
+		break; \
+	} \
+	asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \
+			data->reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+set_temp_reg(MAX, temp_max);
+set_temp_reg(HYST, temp_hyst);
+
+#define sysfs_temp(num) \
+static SENSOR_DEVICE_ATTR(temp##num##_input, S_IRUGO, \
+		show_temp, NULL, num - 1); \
+static SENSOR_DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
+		show_temp_max, set_temp_max, num - 1); \
+static SENSOR_DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
+		show_temp_hyst, set_temp_hyst, num - 1)
+
+sysfs_temp(1);
+sysfs_temp(2);
+sysfs_temp(3);
+sysfs_temp(4);
+
+/* VID */
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* VRM */
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct asb100_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct asb100_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+/* Alarms */
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+/* 1 PWM */
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f));
+}
+
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asb100_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm &= 0x80; /* keep the enable bit */
+	data->pwm |= (0x0f & ASB100_PWM_TO_REG(val));
+	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_enable1(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct asb100_data *data = asb100_update_device(dev);
+	return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0);
+}
+
+static ssize_t set_pwm_enable1(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asb100_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm &= 0x0f; /* keep the duty cycle bits */
+	data->pwm |= (val ? 0x80 : 0x00);
+	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+		show_pwm_enable1, set_pwm_enable1);
+
+static struct attribute *asb100_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_pwm1.attr,
+	&dev_attr_pwm1_enable.attr,
+
+	NULL
+};
+
+static const struct attribute_group asb100_group = {
+	.attrs = asb100_attributes,
+};
+
+static int asb100_detect_subclients(struct i2c_client *client)
+{
+	int i, id, err;
+	int address = client->addr;
+	unsigned short sc_addr[2];
+	struct asb100_data *data = i2c_get_clientdata(client);
+	struct i2c_adapter *adapter = client->adapter;
+
+	id = i2c_adapter_id(adapter);
+
+	if (force_subclients[0] == id && force_subclients[1] == address) {
+		for (i = 2; i <= 3; i++) {
+			if (force_subclients[i] < 0x48 ||
+			    force_subclients[i] > 0x4f) {
+				dev_err(&client->dev,
+					"invalid subclient address %d; must be 0x48-0x4f\n",
+					force_subclients[i]);
+				err = -ENODEV;
+				goto ERROR_SC_2;
+			}
+		}
+		asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
+					(force_subclients[2] & 0x07) |
+					((force_subclients[3] & 0x07) << 4));
+		sc_addr[0] = force_subclients[2];
+		sc_addr[1] = force_subclients[3];
+	} else {
+		int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
+		sc_addr[0] = 0x48 + (val & 0x07);
+		sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
+	}
+
+	if (sc_addr[0] == sc_addr[1]) {
+		dev_err(&client->dev,
+			"duplicate addresses 0x%x for subclients\n",
+			sc_addr[0]);
+		err = -ENODEV;
+		goto ERROR_SC_2;
+	}
+
+	data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
+	if (!data->lm75[0]) {
+		dev_err(&client->dev,
+			"subclient %d registration at address 0x%x failed.\n",
+			1, sc_addr[0]);
+		err = -ENOMEM;
+		goto ERROR_SC_2;
+	}
+
+	data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
+	if (!data->lm75[1]) {
+		dev_err(&client->dev,
+			"subclient %d registration at address 0x%x failed.\n",
+			2, sc_addr[1]);
+		err = -ENOMEM;
+		goto ERROR_SC_3;
+	}
+
+	return 0;
+
+/* Undo inits in case of errors */
+ERROR_SC_3:
+	i2c_unregister_device(data->lm75[0]);
+ERROR_SC_2:
+	return err;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int asb100_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int val1, val2;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_debug("detect failed, smbus byte data not supported!\n");
+		return -ENODEV;
+	}
+
+	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
+	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
+
+	/* If we're in bank 0 */
+	if ((!(val1 & 0x07)) &&
+			/* Check for ASB100 ID (low byte) */
+			(((!(val1 & 0x80)) && (val2 != 0x94)) ||
+			/* Check for ASB100 ID (high byte ) */
+			((val1 & 0x80) && (val2 != 0x06)))) {
+		pr_debug("detect failed, bad chip id 0x%02x!\n", val2);
+		return -ENODEV;
+	}
+
+	/* Put it now into bank 0 and Vendor ID High Byte */
+	i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
+		(i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
+		| 0x80);
+
+	/* Determine the chip type. */
+	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
+	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
+
+	if (val1 != 0x31 || val2 != 0x06)
+		return -ENODEV;
+
+	strlcpy(info->type, "asb100", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int asb100_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int err;
+	struct asb100_data *data;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+
+	/* Attach secondary lm75 clients */
+	err = asb100_detect_subclients(client);
+	if (err)
+		return err;
+
+	/* Initialize the chip */
+	asb100_init_client(client);
+
+	/* A few vars need to be filled upon startup */
+	data->fan_min[0] = asb100_read_value(client, ASB100_REG_FAN_MIN(0));
+	data->fan_min[1] = asb100_read_value(client, ASB100_REG_FAN_MIN(1));
+	data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2));
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &asb100_group);
+	if (err)
+		goto ERROR3;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto ERROR4;
+	}
+
+	return 0;
+
+ERROR4:
+	sysfs_remove_group(&client->dev.kobj, &asb100_group);
+ERROR3:
+	i2c_unregister_device(data->lm75[1]);
+	i2c_unregister_device(data->lm75[0]);
+	return err;
+}
+
+static int asb100_remove(struct i2c_client *client)
+{
+	struct asb100_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &asb100_group);
+
+	i2c_unregister_device(data->lm75[1]);
+	i2c_unregister_device(data->lm75[0]);
+
+	return 0;
+}
+
+/*
+ * The SMBus locks itself, usually, but nothing may access the chip between
+ * bank switches.
+ */
+static int asb100_read_value(struct i2c_client *client, u16 reg)
+{
+	struct asb100_data *data = i2c_get_clientdata(client);
+	struct i2c_client *cl;
+	int res, bank;
+
+	mutex_lock(&data->lock);
+
+	bank = (reg >> 8) & 0x0f;
+	if (bank > 2)
+		/* switch banks */
+		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
+
+	if (bank == 0 || bank > 2) {
+		res = i2c_smbus_read_byte_data(client, reg & 0xff);
+	} else {
+		/* switch to subclient */
+		cl = data->lm75[bank - 1];
+
+		/* convert from ISA to LM75 I2C addresses */
+		switch (reg & 0xff) {
+		case 0x50: /* TEMP */
+			res = i2c_smbus_read_word_swapped(cl, 0);
+			break;
+		case 0x52: /* CONFIG */
+			res = i2c_smbus_read_byte_data(cl, 1);
+			break;
+		case 0x53: /* HYST */
+			res = i2c_smbus_read_word_swapped(cl, 2);
+			break;
+		case 0x55: /* MAX */
+		default:
+			res = i2c_smbus_read_word_swapped(cl, 3);
+			break;
+		}
+	}
+
+	if (bank > 2)
+		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
+
+	mutex_unlock(&data->lock);
+
+	return res;
+}
+
+static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
+{
+	struct asb100_data *data = i2c_get_clientdata(client);
+	struct i2c_client *cl;
+	int bank;
+
+	mutex_lock(&data->lock);
+
+	bank = (reg >> 8) & 0x0f;
+	if (bank > 2)
+		/* switch banks */
+		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
+
+	if (bank == 0 || bank > 2) {
+		i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff);
+	} else {
+		/* switch to subclient */
+		cl = data->lm75[bank - 1];
+
+		/* convert from ISA to LM75 I2C addresses */
+		switch (reg & 0xff) {
+		case 0x52: /* CONFIG */
+			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
+			break;
+		case 0x53: /* HYST */
+			i2c_smbus_write_word_swapped(cl, 2, value);
+			break;
+		case 0x55: /* MAX */
+			i2c_smbus_write_word_swapped(cl, 3, value);
+			break;
+		}
+	}
+
+	if (bank > 2)
+		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
+
+	mutex_unlock(&data->lock);
+}
+
+static void asb100_init_client(struct i2c_client *client)
+{
+	struct asb100_data *data = i2c_get_clientdata(client);
+
+	data->vrm = vid_which_vrm();
+
+	/* Start monitoring */
+	asb100_write_value(client, ASB100_REG_CONFIG,
+		(asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01);
+}
+
+static struct asb100_data *asb100_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asb100_data *data = i2c_get_clientdata(client);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+
+		dev_dbg(&client->dev, "starting device update...\n");
+
+		/* 7 voltage inputs */
+		for (i = 0; i < 7; i++) {
+			data->in[i] = asb100_read_value(client,
+				ASB100_REG_IN(i));
+			data->in_min[i] = asb100_read_value(client,
+				ASB100_REG_IN_MIN(i));
+			data->in_max[i] = asb100_read_value(client,
+				ASB100_REG_IN_MAX(i));
+		}
+
+		/* 3 fan inputs */
+		for (i = 0; i < 3; i++) {
+			data->fan[i] = asb100_read_value(client,
+					ASB100_REG_FAN(i));
+			data->fan_min[i] = asb100_read_value(client,
+					ASB100_REG_FAN_MIN(i));
+		}
+
+		/* 4 temperature inputs */
+		for (i = 1; i <= 4; i++) {
+			data->temp[i-1] = asb100_read_value(client,
+					ASB100_REG_TEMP(i));
+			data->temp_max[i-1] = asb100_read_value(client,
+					ASB100_REG_TEMP_MAX(i));
+			data->temp_hyst[i-1] = asb100_read_value(client,
+					ASB100_REG_TEMP_HYST(i));
+		}
+
+		/* VID and fan divisors */
+		i = asb100_read_value(client, ASB100_REG_VID_FANDIV);
+		data->vid = i & 0x0f;
+		data->vid |= (asb100_read_value(client,
+				ASB100_REG_CHIPID) & 0x01) << 4;
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = (i >> 6) & 0x03;
+		data->fan_div[2] = (asb100_read_value(client,
+				ASB100_REG_PIN) >> 6) & 0x03;
+
+		/* PWM */
+		data->pwm = asb100_read_value(client, ASB100_REG_PWM1);
+
+		/* alarms */
+		data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) +
+			(asb100_read_value(client, ASB100_REG_ALARM2) << 8);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+
+		dev_dbg(&client->dev, "... device update complete\n");
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+module_i2c_driver(asb100_driver);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("ASB100 Bach driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
new file mode 100644
index 0000000..c77644d
--- /dev/null
+++ b/drivers/hwmon/asc7621.c
@@ -0,0 +1,1247 @@
+/*
+ * asc7621.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ * Copyright (c) 2007, 2010 George Joseph  <george.joseph@fairview5.com>
+ *
+ * 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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x2c, 0x2d, 0x2e, I2C_CLIENT_END
+};
+
+enum asc7621_type {
+	asc7621,
+	asc7621a
+};
+
+#define INTERVAL_HIGH   (HZ + HZ / 2)
+#define INTERVAL_LOW    (1 * 60 * HZ)
+#define PRI_NONE        0
+#define PRI_LOW         1
+#define PRI_HIGH        2
+#define FIRST_CHIP      asc7621
+#define LAST_CHIP       asc7621a
+
+struct asc7621_chip {
+	char *name;
+	enum asc7621_type chip_type;
+	u8 company_reg;
+	u8 company_id;
+	u8 verstep_reg;
+	u8 verstep_id;
+	const unsigned short *addresses;
+};
+
+static struct asc7621_chip asc7621_chips[] = {
+	{
+		.name = "asc7621",
+		.chip_type = asc7621,
+		.company_reg = 0x3e,
+		.company_id = 0x61,
+		.verstep_reg = 0x3f,
+		.verstep_id = 0x6c,
+		.addresses = normal_i2c,
+	 },
+	{
+		.name = "asc7621a",
+		.chip_type = asc7621a,
+		.company_reg = 0x3e,
+		.company_id = 0x61,
+		.verstep_reg = 0x3f,
+		.verstep_id = 0x6d,
+		.addresses = normal_i2c,
+	 },
+};
+
+/*
+ * Defines the highest register to be used, not the count.
+ * The actual count will probably be smaller because of gaps
+ * in the implementation (unused register locations).
+ * This define will safely set the array size of both the parameter
+ * and data arrays.
+ * This comes from the data sheet register description table.
+ */
+#define LAST_REGISTER 0xff
+
+struct asc7621_data {
+	struct i2c_client client;
+	struct device *class_dev;
+	struct mutex update_lock;
+	int valid;		/* !=0 if following fields are valid */
+	unsigned long last_high_reading;	/* In jiffies */
+	unsigned long last_low_reading;		/* In jiffies */
+	/*
+	 * Registers we care about occupy the corresponding index
+	 * in the array.  Registers we don't care about are left
+	 * at 0.
+	 */
+	u8 reg[LAST_REGISTER + 1];
+};
+
+/*
+ * Macro to get the parent asc7621_param structure
+ * from a sensor_device_attribute passed into the
+ * show/store functions.
+ */
+#define to_asc7621_param(_sda) \
+	container_of(_sda, struct asc7621_param, sda)
+
+/*
+ * Each parameter to be retrieved needs an asc7621_param structure
+ * allocated.  It contains the sensor_device_attribute structure
+ * and the control info needed to retrieve the value from the register map.
+ */
+struct asc7621_param {
+	struct sensor_device_attribute sda;
+	u8 priority;
+	u8 msb[3];
+	u8 lsb[3];
+	u8 mask[3];
+	u8 shift[3];
+};
+
+/*
+ * This is the map that ultimately indicates whether we'll be
+ * retrieving a register value or not, and at what frequency.
+ */
+static u8 asc7621_register_priorities[255];
+
+static struct asc7621_data *asc7621_update_device(struct device *dev);
+
+static inline u8 read_byte(struct i2c_client *client, u8 reg)
+{
+	int res = i2c_smbus_read_byte_data(client, reg);
+	if (res < 0) {
+		dev_err(&client->dev,
+			"Unable to read from register 0x%02x.\n", reg);
+		return 0;
+	}
+	return res & 0xff;
+}
+
+static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
+{
+	int res = i2c_smbus_write_byte_data(client, reg, data);
+	if (res < 0) {
+		dev_err(&client->dev,
+			"Unable to write value 0x%02x to register 0x%02x.\n",
+			data, reg);
+	}
+	return res;
+}
+
+/*
+ * Data Handlers
+ * Each function handles the formatting, storage
+ * and retrieval of like parameters.
+ */
+
+#define SETUP_SHOW_DATA_PARAM(d, a) \
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
+	struct asc7621_data *data = asc7621_update_device(d); \
+	struct asc7621_param *param = to_asc7621_param(sda)
+
+#define SETUP_STORE_DATA_PARAM(d, a) \
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
+	struct i2c_client *client = to_i2c_client(d); \
+	struct asc7621_data *data = i2c_get_clientdata(client); \
+	struct asc7621_param *param = to_asc7621_param(sda)
+
+/*
+ * u8 is just what it sounds like...an unsigned byte with no
+ * special formatting.
+ */
+static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+
+	return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
+}
+
+static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	reqval = clamp_val(reqval, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->reg[param->msb[0]] = reqval;
+	write_byte(client, param->msb[0], reqval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Many of the config values occupy only a few bits of a register.
+ */
+static ssize_t show_bitmask(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+
+	return sprintf(buf, "%u\n",
+		       (data->reg[param->msb[0]] >> param->
+			shift[0]) & param->mask[0]);
+}
+
+static ssize_t store_bitmask(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	u8 currval;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	reqval = clamp_val(reqval, 0, param->mask[0]);
+
+	reqval = (reqval & param->mask[0]) << param->shift[0];
+
+	mutex_lock(&data->update_lock);
+	currval = read_byte(client, param->msb[0]);
+	reqval |= (currval & ~(param->mask[0] << param->shift[0]));
+	data->reg[param->msb[0]] = reqval;
+	write_byte(client, param->msb[0], reqval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * 16 bit fan rpm values
+ * reported by the device as the number of 11.111us periods (90khz)
+ * between full fan rotations.  Therefore...
+ * RPM = (90000 * 60) / register value
+ */
+static ssize_t show_fan16(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u16 regval;
+
+	mutex_lock(&data->update_lock);
+	regval = (data->reg[param->msb[0]] << 8) | data->reg[param->lsb[0]];
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n",
+		       (regval == 0 ? -1 : (regval) ==
+			0xffff ? 0 : 5400000 / regval));
+}
+
+static ssize_t store_fan16(struct device *dev,
+			   struct device_attribute *attr, const char *buf,
+			   size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	/*
+	 * If a minimum RPM of zero is requested, then we set the register to
+	 * 0xffff. This value allows the fan to be stopped completely without
+	 * generating an alarm.
+	 */
+	reqval =
+	    (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe));
+
+	mutex_lock(&data->update_lock);
+	data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
+	data->reg[param->lsb[0]] = reqval & 0xff;
+	write_byte(client, param->msb[0], data->reg[param->msb[0]]);
+	write_byte(client, param->lsb[0], data->reg[param->lsb[0]]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Voltages are scaled in the device so that the nominal voltage
+ * is 3/4ths of the 0-255 range (i.e. 192).
+ * If all voltages are 'normal' then all voltage registers will
+ * read 0xC0.
+ *
+ * The data sheet provides us with the 3/4 scale value for each voltage
+ * which is stored in in_scaling.  The sda->index parameter value provides
+ * the index into in_scaling.
+ *
+ * NOTE: The chip expects the first 2 inputs be 2.5 and 2.25 volts
+ * respectively. That doesn't mean that's what the motherboard provides. :)
+ */
+
+static const int asc7621_in_scaling[] = {
+	2500, 2250, 3300, 5000, 12000
+};
+
+static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u16 regval;
+	u8 nr = sda->index;
+
+	mutex_lock(&data->update_lock);
+	regval = (data->reg[param->msb[0]] << 8) | (data->reg[param->lsb[0]]);
+	mutex_unlock(&data->update_lock);
+
+	/* The LSB value is a 2-bit scaling of the MSB's LSbit value. */
+	regval = (regval >> 6) * asc7621_in_scaling[nr] / (0xc0 << 2);
+
+	return sprintf(buf, "%u\n", regval);
+}
+
+/* 8 bit voltage values (the mins and maxs) */
+static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 nr = sda->index;
+
+	return sprintf(buf, "%u\n",
+		       ((data->reg[param->msb[0]] *
+			 asc7621_in_scaling[nr]) / 0xc0));
+}
+
+static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	u8 nr = sda->index;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	reqval = clamp_val(reqval, 0, 0xffff);
+
+	reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
+
+	reqval = clamp_val(reqval, 0, 0xff);
+
+	mutex_lock(&data->update_lock);
+	data->reg[param->msb[0]] = reqval;
+	write_byte(client, param->msb[0], reqval);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp8(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+
+	return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
+}
+
+static ssize_t store_temp8(struct device *dev,
+			   struct device_attribute *attr, const char *buf,
+			   size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	s8 temp;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	reqval = clamp_val(reqval, -127000, 127000);
+
+	temp = reqval / 1000;
+
+	mutex_lock(&data->update_lock);
+	data->reg[param->msb[0]] = temp;
+	write_byte(client, param->msb[0], temp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Temperatures that occupy 2 bytes always have the whole
+ * number of degrees in the MSB with some part of the LSB
+ * indicating fractional degrees.
+ */
+
+/*   mmmmmmmm.llxxxxxx */
+static ssize_t show_temp10(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 msb, lsb;
+	int temp;
+
+	mutex_lock(&data->update_lock);
+	msb = data->reg[param->msb[0]];
+	lsb = (data->reg[param->lsb[0]] >> 6) & 0x03;
+	temp = (((s8) msb) * 1000) + (lsb * 250);
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+/*   mmmmmm.ll */
+static ssize_t show_temp62(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 regval = data->reg[param->msb[0]];
+	int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t store_temp62(struct device *dev,
+			    struct device_attribute *attr, const char *buf,
+			    size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval, i, f;
+	s8 temp;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	reqval = clamp_val(reqval, -32000, 31750);
+	i = reqval / 1000;
+	f = reqval - (i * 1000);
+	temp = i << 2;
+	temp |= f / 250;
+
+	mutex_lock(&data->update_lock);
+	data->reg[param->msb[0]] = temp;
+	write_byte(client, param->msb[0], temp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * The aSC7621 doesn't provide an "auto_point2".  Instead, you
+ * specify the auto_point1 and a range.  To keep with the sysfs
+ * hwmon specs, we synthesize the auto_point_2 from them.
+ */
+
+static const u32 asc7621_range_map[] = {
+	2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000,
+	13330, 16000, 20000, 26670, 32000, 40000, 53330, 80000,
+};
+
+static ssize_t show_ap2_temp(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	long auto_point1;
+	u8 regval;
+	int temp;
+
+	mutex_lock(&data->update_lock);
+	auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
+	regval =
+	    ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
+	temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)];
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp);
+
+}
+
+static ssize_t store_ap2_temp(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval, auto_point1;
+	int i;
+	u8 currval, newval = 0;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	auto_point1 = data->reg[param->msb[1]] * 1000;
+	reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000);
+
+	for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
+		if (reqval >= auto_point1 + asc7621_range_map[i]) {
+			newval = i;
+			break;
+		}
+	}
+
+	newval = (newval & param->mask[0]) << param->shift[0];
+	currval = read_byte(client, param->msb[0]);
+	newval |= (currval & ~(param->mask[0] << param->shift[0]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_ac(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 config, altbit, regval;
+	const u8 map[] = {
+		0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
+		0x08, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+	};
+
+	mutex_lock(&data->update_lock);
+	config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+	altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
+	regval = config | (altbit << 3);
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]);
+}
+
+static ssize_t store_pwm_ac(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	unsigned long reqval;
+	u8 currval, config, altbit, newval;
+	const u16 map[] = {
+		0x04, 0x00, 0x01, 0xff, 0x02, 0xff, 0x05, 0x06,
+		0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+		0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+	};
+
+	if (kstrtoul(buf, 10, &reqval))
+		return -EINVAL;
+
+	if (reqval > 31)
+		return -EINVAL;
+
+	reqval = map[reqval];
+	if (reqval == 0xff)
+		return -EINVAL;
+
+	config = reqval & 0x07;
+	altbit = (reqval >> 3) & 0x01;
+
+	config = (config & param->mask[0]) << param->shift[0];
+	altbit = (altbit & param->mask[1]) << param->shift[1];
+
+	mutex_lock(&data->update_lock);
+	currval = read_byte(client, param->msb[0]);
+	newval = config | (currval & ~(param->mask[0] << param->shift[0]));
+	newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 config, altbit, minoff, val, newval;
+
+	mutex_lock(&data->update_lock);
+	config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+	altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
+	minoff = (data->reg[param->msb[2]] >> param->shift[2]) & param->mask[2];
+	mutex_unlock(&data->update_lock);
+
+	val = config | (altbit << 3);
+	newval = 0;
+
+	if (val == 3 || val >= 10)
+		newval = 255;
+	else if (val == 4)
+		newval = 0;
+	else if (val == 7)
+		newval = 1;
+	else if (minoff == 1)
+		newval = 2;
+	else
+		newval = 3;
+
+	return sprintf(buf, "%u\n", newval);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	u8 currval, config, altbit, newval, minoff = 255;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	switch (reqval) {
+	case 0:
+		newval = 0x04;
+		break;
+	case 1:
+		newval = 0x07;
+		break;
+	case 2:
+		newval = 0x00;
+		minoff = 1;
+		break;
+	case 3:
+		newval = 0x00;
+		minoff = 0;
+		break;
+	case 255:
+		newval = 0x03;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	config = newval & 0x07;
+	altbit = (newval >> 3) & 0x01;
+
+	mutex_lock(&data->update_lock);
+	config = (config & param->mask[0]) << param->shift[0];
+	altbit = (altbit & param->mask[1]) << param->shift[1];
+	currval = read_byte(client, param->msb[0]);
+	newval = config | (currval & ~(param->mask[0] << param->shift[0]));
+	newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	if (minoff < 255) {
+		minoff = (minoff & param->mask[2]) << param->shift[2];
+		currval = read_byte(client, param->msb[2]);
+		newval =
+		    minoff | (currval & ~(param->mask[2] << param->shift[2]));
+		data->reg[param->msb[2]] = newval;
+		write_byte(client, param->msb[2], newval);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static const u32 asc7621_pwm_freq_map[] = {
+	10, 15, 23, 30, 38, 47, 62, 94,
+	23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000
+};
+
+static ssize_t show_pwm_freq(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 regval =
+	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+
+	regval = clamp_val(regval, 0, 15);
+
+	return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	unsigned long reqval;
+	u8 currval, newval = 255;
+	int i;
+
+	if (kstrtoul(buf, 10, &reqval))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(asc7621_pwm_freq_map); i++) {
+		if (reqval == asc7621_pwm_freq_map[i]) {
+			newval = i;
+			break;
+		}
+	}
+	if (newval == 255)
+		return -EINVAL;
+
+	newval = (newval & param->mask[0]) << param->shift[0];
+
+	mutex_lock(&data->update_lock);
+	currval = read_byte(client, param->msb[0]);
+	newval |= (currval & ~(param->mask[0] << param->shift[0]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static const u32 asc7621_pwm_auto_spinup_map[] =  {
+	0, 100, 250, 400, 700, 1000, 2000, 4000
+};
+
+static ssize_t show_pwm_ast(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 regval =
+	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+
+	regval = clamp_val(regval, 0, 7);
+
+	return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
+
+}
+
+static ssize_t store_pwm_ast(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	u8 currval, newval = 255;
+	u32 i;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(asc7621_pwm_auto_spinup_map); i++) {
+		if (reqval == asc7621_pwm_auto_spinup_map[i]) {
+			newval = i;
+			break;
+		}
+	}
+	if (newval == 255)
+		return -EINVAL;
+
+	newval = (newval & param->mask[0]) << param->shift[0];
+
+	mutex_lock(&data->update_lock);
+	currval = read_byte(client, param->msb[0]);
+	newval |= (currval & ~(param->mask[0] << param->shift[0]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static const u32 asc7621_temp_smoothing_time_map[] = {
+	35000, 17600, 11800, 7000, 4400, 3000, 1600, 800
+};
+
+static ssize_t show_temp_st(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	SETUP_SHOW_DATA_PARAM(dev, attr);
+	u8 regval =
+	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+	regval = clamp_val(regval, 0, 7);
+
+	return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
+}
+
+static ssize_t store_temp_st(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	SETUP_STORE_DATA_PARAM(dev, attr);
+	long reqval;
+	u8 currval, newval = 255;
+	u32 i;
+
+	if (kstrtol(buf, 10, &reqval))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(asc7621_temp_smoothing_time_map); i++) {
+		if (reqval == asc7621_temp_smoothing_time_map[i]) {
+			newval = i;
+			break;
+		}
+	}
+
+	if (newval == 255)
+		return -EINVAL;
+
+	newval = (newval & param->mask[0]) << param->shift[0];
+
+	mutex_lock(&data->update_lock);
+	currval = read_byte(client, param->msb[0]);
+	newval |= (currval & ~(param->mask[0] << param->shift[0]));
+	data->reg[param->msb[0]] = newval;
+	write_byte(client, param->msb[0], newval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * End of data handlers
+ *
+ * These defines do nothing more than make the table easier
+ * to read when wrapped at column 80.
+ */
+
+/*
+ * Creates a variable length array inititalizer.
+ * VAA(1,3,5,7) would produce {1,3,5,7}
+ */
+#define VAA(args...) {args}
+
+#define PREAD(name, n, pri, rm, rl, m, s, r) \
+	{.sda = SENSOR_ATTR(name, S_IRUGO, show_##r, NULL, n), \
+	  .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
+	  .shift[0] = s,}
+
+#define PWRITE(name, n, pri, rm, rl, m, s, r) \
+	{.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
+	  .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
+	  .shift[0] = s,}
+
+/*
+ * PWRITEM assumes that the initializers for the .msb, .lsb, .mask and .shift
+ * were created using the VAA macro.
+ */
+#define PWRITEM(name, n, pri, rm, rl, m, s, r) \
+	{.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
+	  .priority = pri, .msb = rm, .lsb = rl, .mask = m, .shift = s,}
+
+static struct asc7621_param asc7621_params[] = {
+	PREAD(in0_input, 0, PRI_HIGH, 0x20, 0x13, 0, 0, in10),
+	PREAD(in1_input, 1, PRI_HIGH, 0x21, 0x18, 0, 0, in10),
+	PREAD(in2_input, 2, PRI_HIGH, 0x22, 0x11, 0, 0, in10),
+	PREAD(in3_input, 3, PRI_HIGH, 0x23, 0x12, 0, 0, in10),
+	PREAD(in4_input, 4, PRI_HIGH, 0x24, 0x14, 0, 0, in10),
+
+	PWRITE(in0_min, 0, PRI_LOW, 0x44, 0, 0, 0, in8),
+	PWRITE(in1_min, 1, PRI_LOW, 0x46, 0, 0, 0, in8),
+	PWRITE(in2_min, 2, PRI_LOW, 0x48, 0, 0, 0, in8),
+	PWRITE(in3_min, 3, PRI_LOW, 0x4a, 0, 0, 0, in8),
+	PWRITE(in4_min, 4, PRI_LOW, 0x4c, 0, 0, 0, in8),
+
+	PWRITE(in0_max, 0, PRI_LOW, 0x45, 0, 0, 0, in8),
+	PWRITE(in1_max, 1, PRI_LOW, 0x47, 0, 0, 0, in8),
+	PWRITE(in2_max, 2, PRI_LOW, 0x49, 0, 0, 0, in8),
+	PWRITE(in3_max, 3, PRI_LOW, 0x4b, 0, 0, 0, in8),
+	PWRITE(in4_max, 4, PRI_LOW, 0x4d, 0, 0, 0, in8),
+
+	PREAD(in0_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 0, bitmask),
+	PREAD(in1_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 1, bitmask),
+	PREAD(in2_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 2, bitmask),
+	PREAD(in3_alarm, 3, PRI_HIGH, 0x41, 0, 0x01, 3, bitmask),
+	PREAD(in4_alarm, 4, PRI_HIGH, 0x42, 0, 0x01, 0, bitmask),
+
+	PREAD(fan1_input, 0, PRI_HIGH, 0x29, 0x28, 0, 0, fan16),
+	PREAD(fan2_input, 1, PRI_HIGH, 0x2b, 0x2a, 0, 0, fan16),
+	PREAD(fan3_input, 2, PRI_HIGH, 0x2d, 0x2c, 0, 0, fan16),
+	PREAD(fan4_input, 3, PRI_HIGH, 0x2f, 0x2e, 0, 0, fan16),
+
+	PWRITE(fan1_min, 0, PRI_LOW, 0x55, 0x54, 0, 0, fan16),
+	PWRITE(fan2_min, 1, PRI_LOW, 0x57, 0x56, 0, 0, fan16),
+	PWRITE(fan3_min, 2, PRI_LOW, 0x59, 0x58, 0, 0, fan16),
+	PWRITE(fan4_min, 3, PRI_LOW, 0x5b, 0x5a, 0, 0, fan16),
+
+	PREAD(fan1_alarm, 0, PRI_HIGH, 0x42, 0, 0x01, 2, bitmask),
+	PREAD(fan2_alarm, 1, PRI_HIGH, 0x42, 0, 0x01, 3, bitmask),
+	PREAD(fan3_alarm, 2, PRI_HIGH, 0x42, 0, 0x01, 4, bitmask),
+	PREAD(fan4_alarm, 3, PRI_HIGH, 0x42, 0, 0x01, 5, bitmask),
+
+	PREAD(temp1_input, 0, PRI_HIGH, 0x25, 0x10, 0, 0, temp10),
+	PREAD(temp2_input, 1, PRI_HIGH, 0x26, 0x15, 0, 0, temp10),
+	PREAD(temp3_input, 2, PRI_HIGH, 0x27, 0x16, 0, 0, temp10),
+	PREAD(temp4_input, 3, PRI_HIGH, 0x33, 0x17, 0, 0, temp10),
+	PREAD(temp5_input, 4, PRI_HIGH, 0xf7, 0xf6, 0, 0, temp10),
+	PREAD(temp6_input, 5, PRI_HIGH, 0xf9, 0xf8, 0, 0, temp10),
+	PREAD(temp7_input, 6, PRI_HIGH, 0xfb, 0xfa, 0, 0, temp10),
+	PREAD(temp8_input, 7, PRI_HIGH, 0xfd, 0xfc, 0, 0, temp10),
+
+	PWRITE(temp1_min, 0, PRI_LOW, 0x4e, 0, 0, 0, temp8),
+	PWRITE(temp2_min, 1, PRI_LOW, 0x50, 0, 0, 0, temp8),
+	PWRITE(temp3_min, 2, PRI_LOW, 0x52, 0, 0, 0, temp8),
+	PWRITE(temp4_min, 3, PRI_LOW, 0x34, 0, 0, 0, temp8),
+
+	PWRITE(temp1_max, 0, PRI_LOW, 0x4f, 0, 0, 0, temp8),
+	PWRITE(temp2_max, 1, PRI_LOW, 0x51, 0, 0, 0, temp8),
+	PWRITE(temp3_max, 2, PRI_LOW, 0x53, 0, 0, 0, temp8),
+	PWRITE(temp4_max, 3, PRI_LOW, 0x35, 0, 0, 0, temp8),
+
+	PREAD(temp1_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 4, bitmask),
+	PREAD(temp2_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 5, bitmask),
+	PREAD(temp3_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 6, bitmask),
+	PREAD(temp4_alarm, 3, PRI_HIGH, 0x43, 0, 0x01, 0, bitmask),
+
+	PWRITE(temp1_source, 0, PRI_LOW, 0x02, 0, 0x07, 4, bitmask),
+	PWRITE(temp2_source, 1, PRI_LOW, 0x02, 0, 0x07, 0, bitmask),
+	PWRITE(temp3_source, 2, PRI_LOW, 0x03, 0, 0x07, 4, bitmask),
+	PWRITE(temp4_source, 3, PRI_LOW, 0x03, 0, 0x07, 0, bitmask),
+
+	PWRITE(temp1_smoothing_enable, 0, PRI_LOW, 0x62, 0, 0x01, 3, bitmask),
+	PWRITE(temp2_smoothing_enable, 1, PRI_LOW, 0x63, 0, 0x01, 7, bitmask),
+	PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x63, 0, 0x01, 3, bitmask),
+	PWRITE(temp4_smoothing_enable, 3, PRI_LOW, 0x3c, 0, 0x01, 3, bitmask),
+
+	PWRITE(temp1_smoothing_time, 0, PRI_LOW, 0x62, 0, 0x07, 0, temp_st),
+	PWRITE(temp2_smoothing_time, 1, PRI_LOW, 0x63, 0, 0x07, 4, temp_st),
+	PWRITE(temp3_smoothing_time, 2, PRI_LOW, 0x63, 0, 0x07, 0, temp_st),
+	PWRITE(temp4_smoothing_time, 3, PRI_LOW, 0x3c, 0, 0x07, 0, temp_st),
+
+	PWRITE(temp1_auto_point1_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
+	       bitmask),
+	PWRITE(temp2_auto_point1_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
+	       bitmask),
+	PWRITE(temp3_auto_point1_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
+	       bitmask),
+	PWRITE(temp4_auto_point1_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
+	       bitmask),
+
+	PREAD(temp1_auto_point2_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
+	      bitmask),
+	PREAD(temp2_auto_point2_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
+	      bitmask),
+	PREAD(temp3_auto_point2_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
+	      bitmask),
+	PREAD(temp4_auto_point2_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
+	      bitmask),
+
+	PWRITE(temp1_auto_point1_temp, 0, PRI_LOW, 0x67, 0, 0, 0, temp8),
+	PWRITE(temp2_auto_point1_temp, 1, PRI_LOW, 0x68, 0, 0, 0, temp8),
+	PWRITE(temp3_auto_point1_temp, 2, PRI_LOW, 0x69, 0, 0, 0, temp8),
+	PWRITE(temp4_auto_point1_temp, 3, PRI_LOW, 0x3b, 0, 0, 0, temp8),
+
+	PWRITEM(temp1_auto_point2_temp, 0, PRI_LOW, VAA(0x5f, 0x67), VAA(0),
+		VAA(0x0f), VAA(4), ap2_temp),
+	PWRITEM(temp2_auto_point2_temp, 1, PRI_LOW, VAA(0x60, 0x68), VAA(0),
+		VAA(0x0f), VAA(4), ap2_temp),
+	PWRITEM(temp3_auto_point2_temp, 2, PRI_LOW, VAA(0x61, 0x69), VAA(0),
+		VAA(0x0f), VAA(4), ap2_temp),
+	PWRITEM(temp4_auto_point2_temp, 3, PRI_LOW, VAA(0x3c, 0x3b), VAA(0),
+		VAA(0x0f), VAA(4), ap2_temp),
+
+	PWRITE(temp1_crit, 0, PRI_LOW, 0x6a, 0, 0, 0, temp8),
+	PWRITE(temp2_crit, 1, PRI_LOW, 0x6b, 0, 0, 0, temp8),
+	PWRITE(temp3_crit, 2, PRI_LOW, 0x6c, 0, 0, 0, temp8),
+	PWRITE(temp4_crit, 3, PRI_LOW, 0x3d, 0, 0, 0, temp8),
+
+	PWRITE(temp5_enable, 4, PRI_LOW, 0x0e, 0, 0x01, 0, bitmask),
+	PWRITE(temp6_enable, 5, PRI_LOW, 0x0e, 0, 0x01, 1, bitmask),
+	PWRITE(temp7_enable, 6, PRI_LOW, 0x0e, 0, 0x01, 2, bitmask),
+	PWRITE(temp8_enable, 7, PRI_LOW, 0x0e, 0, 0x01, 3, bitmask),
+
+	PWRITE(remote1_offset, 0, PRI_LOW, 0x1c, 0, 0, 0, temp62),
+	PWRITE(remote2_offset, 1, PRI_LOW, 0x1d, 0, 0, 0, temp62),
+
+	PWRITE(pwm1, 0, PRI_HIGH, 0x30, 0, 0, 0, u8),
+	PWRITE(pwm2, 1, PRI_HIGH, 0x31, 0, 0, 0, u8),
+	PWRITE(pwm3, 2, PRI_HIGH, 0x32, 0, 0, 0, u8),
+
+	PWRITE(pwm1_invert, 0, PRI_LOW, 0x5c, 0, 0x01, 4, bitmask),
+	PWRITE(pwm2_invert, 1, PRI_LOW, 0x5d, 0, 0x01, 4, bitmask),
+	PWRITE(pwm3_invert, 2, PRI_LOW, 0x5e, 0, 0x01, 4, bitmask),
+
+	PWRITEM(pwm1_enable, 0, PRI_LOW, VAA(0x5c, 0x5c, 0x62), VAA(0, 0, 0),
+		VAA(0x07, 0x01, 0x01), VAA(5, 3, 5), pwm_enable),
+	PWRITEM(pwm2_enable, 1, PRI_LOW, VAA(0x5d, 0x5d, 0x62), VAA(0, 0, 0),
+		VAA(0x07, 0x01, 0x01), VAA(5, 3, 6), pwm_enable),
+	PWRITEM(pwm3_enable, 2, PRI_LOW, VAA(0x5e, 0x5e, 0x62), VAA(0, 0, 0),
+		VAA(0x07, 0x01, 0x01), VAA(5, 3, 7), pwm_enable),
+
+	PWRITEM(pwm1_auto_channels, 0, PRI_LOW, VAA(0x5c, 0x5c), VAA(0, 0),
+		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+	PWRITEM(pwm2_auto_channels, 1, PRI_LOW, VAA(0x5d, 0x5d), VAA(0, 0),
+		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+	PWRITEM(pwm3_auto_channels, 2, PRI_LOW, VAA(0x5e, 0x5e), VAA(0, 0),
+		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+
+	PWRITE(pwm1_auto_point1_pwm, 0, PRI_LOW, 0x64, 0, 0, 0, u8),
+	PWRITE(pwm2_auto_point1_pwm, 1, PRI_LOW, 0x65, 0, 0, 0, u8),
+	PWRITE(pwm3_auto_point1_pwm, 2, PRI_LOW, 0x66, 0, 0, 0, u8),
+
+	PWRITE(pwm1_auto_point2_pwm, 0, PRI_LOW, 0x38, 0, 0, 0, u8),
+	PWRITE(pwm2_auto_point2_pwm, 1, PRI_LOW, 0x39, 0, 0, 0, u8),
+	PWRITE(pwm3_auto_point2_pwm, 2, PRI_LOW, 0x3a, 0, 0, 0, u8),
+
+	PWRITE(pwm1_freq, 0, PRI_LOW, 0x5f, 0, 0x0f, 0, pwm_freq),
+	PWRITE(pwm2_freq, 1, PRI_LOW, 0x60, 0, 0x0f, 0, pwm_freq),
+	PWRITE(pwm3_freq, 2, PRI_LOW, 0x61, 0, 0x0f, 0, pwm_freq),
+
+	PREAD(pwm1_auto_zone_assigned, 0, PRI_LOW, 0, 0, 0x03, 2, bitmask),
+	PREAD(pwm2_auto_zone_assigned, 1, PRI_LOW, 0, 0, 0x03, 4, bitmask),
+	PREAD(pwm3_auto_zone_assigned, 2, PRI_LOW, 0, 0, 0x03, 6, bitmask),
+
+	PWRITE(pwm1_auto_spinup_time, 0, PRI_LOW, 0x5c, 0, 0x07, 0, pwm_ast),
+	PWRITE(pwm2_auto_spinup_time, 1, PRI_LOW, 0x5d, 0, 0x07, 0, pwm_ast),
+	PWRITE(pwm3_auto_spinup_time, 2, PRI_LOW, 0x5e, 0, 0x07, 0, pwm_ast),
+
+	PWRITE(peci_enable, 0, PRI_LOW, 0x40, 0, 0x01, 4, bitmask),
+	PWRITE(peci_avg, 0, PRI_LOW, 0x36, 0, 0x07, 0, bitmask),
+	PWRITE(peci_domain, 0, PRI_LOW, 0x36, 0, 0x01, 3, bitmask),
+	PWRITE(peci_legacy, 0, PRI_LOW, 0x36, 0, 0x01, 4, bitmask),
+	PWRITE(peci_diode, 0, PRI_LOW, 0x0e, 0, 0x07, 4, bitmask),
+	PWRITE(peci_4domain, 0, PRI_LOW, 0x0e, 0, 0x01, 4, bitmask),
+
+};
+
+static struct asc7621_data *asc7621_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct asc7621_data *data = i2c_get_clientdata(client);
+	int i;
+
+/*
+ * The asc7621 chips guarantee consistent reads of multi-byte values
+ * regardless of the order of the reads.  No special logic is needed
+ * so we can just read the registers in whatever  order they appear
+ * in the asc7621_params array.
+ */
+
+	mutex_lock(&data->update_lock);
+
+	/* Read all the high priority registers */
+
+	if (!data->valid ||
+	    time_after(jiffies, data->last_high_reading + INTERVAL_HIGH)) {
+
+		for (i = 0; i < ARRAY_SIZE(asc7621_register_priorities); i++) {
+			if (asc7621_register_priorities[i] == PRI_HIGH) {
+				data->reg[i] =
+				    i2c_smbus_read_byte_data(client, i) & 0xff;
+			}
+		}
+		data->last_high_reading = jiffies;
+	}			/* last_reading */
+
+	/* Read all the low priority registers. */
+
+	if (!data->valid ||
+	    time_after(jiffies, data->last_low_reading + INTERVAL_LOW)) {
+
+		for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+			if (asc7621_register_priorities[i] == PRI_LOW) {
+				data->reg[i] =
+				    i2c_smbus_read_byte_data(client, i) & 0xff;
+			}
+		}
+		data->last_low_reading = jiffies;
+	}			/* last_reading */
+
+	data->valid = 1;
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Standard detection and initialization below
+ *
+ * Helper function that checks if an address is valid
+ * for a particular chip.
+ */
+
+static inline int valid_address_for_chip(int chip_type, int address)
+{
+	int i;
+
+	for (i = 0; asc7621_chips[chip_type].addresses[i] != I2C_CLIENT_END;
+	     i++) {
+		if (asc7621_chips[chip_type].addresses[i] == address)
+			return 1;
+	}
+	return 0;
+}
+
+static void asc7621_init_client(struct i2c_client *client)
+{
+	int value;
+
+	/* Warn if part was not "READY" */
+
+	value = read_byte(client, 0x40);
+
+	if (value & 0x02) {
+		dev_err(&client->dev,
+			"Client (%d,0x%02x) config is locked.\n",
+			i2c_adapter_id(client->adapter), client->addr);
+	}
+	if (!(value & 0x04)) {
+		dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n",
+			i2c_adapter_id(client->adapter), client->addr);
+	}
+
+/*
+ * Start monitoring
+ *
+ * Try to clear LOCK, Set START, save everything else
+ */
+	value = (value & ~0x02) | 0x01;
+	write_byte(client, 0x40, value & 0xff);
+
+}
+
+static int
+asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct asc7621_data *data;
+	int i, err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct asc7621_data),
+			    GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the asc7621 chip */
+	asc7621_init_client(client);
+
+	/* Create the sysfs entries */
+	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+		err =
+		    device_create_file(&client->dev,
+				       &(asc7621_params[i].sda.dev_attr));
+		if (err)
+			goto exit_remove;
+	}
+
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+		device_remove_file(&client->dev,
+				   &(asc7621_params[i].sda.dev_attr));
+	}
+
+	return err;
+}
+
+static int asc7621_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int company, verstep, chip_index;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	for (chip_index = FIRST_CHIP; chip_index <= LAST_CHIP; chip_index++) {
+
+		if (!valid_address_for_chip(chip_index, client->addr))
+			continue;
+
+		company = read_byte(client,
+			asc7621_chips[chip_index].company_reg);
+		verstep = read_byte(client,
+			asc7621_chips[chip_index].verstep_reg);
+
+		if (company == asc7621_chips[chip_index].company_id &&
+		    verstep == asc7621_chips[chip_index].verstep_id) {
+			strlcpy(info->type, asc7621_chips[chip_index].name,
+				I2C_NAME_SIZE);
+
+			dev_info(&adapter->dev, "Matched %s at 0x%02x\n",
+				 asc7621_chips[chip_index].name, client->addr);
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+static int asc7621_remove(struct i2c_client *client)
+{
+	struct asc7621_data *data = i2c_get_clientdata(client);
+	int i;
+
+	hwmon_device_unregister(data->class_dev);
+
+	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+		device_remove_file(&client->dev,
+				   &(asc7621_params[i].sda.dev_attr));
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id asc7621_id[] = {
+	{"asc7621", asc7621},
+	{"asc7621a", asc7621a},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, asc7621_id);
+
+static struct i2c_driver asc7621_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "asc7621",
+	},
+	.probe = asc7621_probe,
+	.remove = asc7621_remove,
+	.id_table = asc7621_id,
+	.detect = asc7621_detect,
+	.address_list = normal_i2c,
+};
+
+static int __init sm_asc7621_init(void)
+{
+	int i, j;
+/*
+ * Collect all the registers needed into a single array.
+ * This way, if a register isn't actually used for anything,
+ * we don't retrieve it.
+ */
+
+	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+		for (j = 0; j < ARRAY_SIZE(asc7621_params[i].msb); j++)
+			asc7621_register_priorities[asc7621_params[i].msb[j]] =
+			    asc7621_params[i].priority;
+		for (j = 0; j < ARRAY_SIZE(asc7621_params[i].lsb); j++)
+			asc7621_register_priorities[asc7621_params[i].lsb[j]] =
+			    asc7621_params[i].priority;
+	}
+	return i2c_add_driver(&asc7621_driver);
+}
+
+static void __exit sm_asc7621_exit(void)
+{
+	i2c_del_driver(&asc7621_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("George Joseph");
+MODULE_DESCRIPTION("Andigilog aSC7621 and aSC7621a driver");
+
+module_init(sm_asc7621_init);
+module_exit(sm_asc7621_exit);
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
new file mode 100644
index 0000000..cccef87
--- /dev/null
+++ b/drivers/hwmon/asus_atk0110.c
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
+ *
+ * This file is released under the GPLv2
+ * See COPYING in the top level directory of the kernel tree.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include <linux/acpi.h>
+
+#define ATK_HID "ATK0110"
+
+static bool new_if;
+module_param(new_if, bool, 0);
+MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
+
+static const struct dmi_system_id __initconst atk_force_new_if[] = {
+	{
+		/* Old interface has broken MCH temp monitoring */
+		.ident = "Asus Sabertooth X58",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
+		}
+	}, {
+		/* Old interface reads the same sensor for fan0 and fan1 */
+		.ident = "Asus M5A78L",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "M5A78L")
+		}
+	},
+	{ }
+};
+
+/*
+ * Minimum time between readings, enforced in order to avoid
+ * hogging the CPU.
+ */
+#define CACHE_TIME		HZ
+
+#define BOARD_ID		"MBIF"
+#define METHOD_ENUMERATE	"GGRP"
+#define METHOD_READ		"GITM"
+#define METHOD_WRITE		"SITM"
+#define METHOD_OLD_READ_TMP	"RTMP"
+#define METHOD_OLD_READ_VLT	"RVLT"
+#define METHOD_OLD_READ_FAN	"RFAN"
+#define METHOD_OLD_ENUM_TMP	"TSIF"
+#define METHOD_OLD_ENUM_VLT	"VSIF"
+#define METHOD_OLD_ENUM_FAN	"FSIF"
+
+#define ATK_MUX_HWMON		0x00000006ULL
+#define ATK_MUX_MGMT		0x00000011ULL
+
+#define ATK_CLASS_MASK		0xff000000ULL
+#define ATK_CLASS_FREQ_CTL	0x03000000ULL
+#define ATK_CLASS_FAN_CTL	0x04000000ULL
+#define ATK_CLASS_HWMON		0x06000000ULL
+#define ATK_CLASS_MGMT		0x11000000ULL
+
+#define ATK_TYPE_MASK		0x00ff0000ULL
+#define HWMON_TYPE_VOLT		0x00020000ULL
+#define HWMON_TYPE_TEMP		0x00030000ULL
+#define HWMON_TYPE_FAN		0x00040000ULL
+
+#define ATK_ELEMENT_ID_MASK	0x0000ffffULL
+
+#define ATK_EC_ID		0x11060004ULL
+
+enum atk_pack_member {
+	HWMON_PACK_FLAGS,
+	HWMON_PACK_NAME,
+	HWMON_PACK_LIMIT1,
+	HWMON_PACK_LIMIT2,
+	HWMON_PACK_ENABLE
+};
+
+/* New package format */
+#define _HWMON_NEW_PACK_SIZE	7
+#define _HWMON_NEW_PACK_FLAGS	0
+#define _HWMON_NEW_PACK_NAME	1
+#define _HWMON_NEW_PACK_UNK1	2
+#define _HWMON_NEW_PACK_UNK2	3
+#define _HWMON_NEW_PACK_LIMIT1	4
+#define _HWMON_NEW_PACK_LIMIT2	5
+#define _HWMON_NEW_PACK_ENABLE	6
+
+/* Old package format */
+#define _HWMON_OLD_PACK_SIZE	5
+#define _HWMON_OLD_PACK_FLAGS	0
+#define _HWMON_OLD_PACK_NAME	1
+#define _HWMON_OLD_PACK_LIMIT1	2
+#define _HWMON_OLD_PACK_LIMIT2	3
+#define _HWMON_OLD_PACK_ENABLE	4
+
+
+struct atk_data {
+	struct device *hwmon_dev;
+	acpi_handle atk_handle;
+	struct acpi_device *acpi_dev;
+
+	bool old_interface;
+
+	/* old interface */
+	acpi_handle rtmp_handle;
+	acpi_handle rvlt_handle;
+	acpi_handle rfan_handle;
+	/* new interface */
+	acpi_handle enumerate_handle;
+	acpi_handle read_handle;
+	acpi_handle write_handle;
+
+	bool disable_ec;
+
+	int voltage_count;
+	int temperature_count;
+	int fan_count;
+	struct list_head sensor_list;
+
+	struct {
+		struct dentry *root;
+		u32 id;
+	} debugfs;
+};
+
+
+typedef ssize_t (*sysfs_show_func)(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+static const struct acpi_device_id atk_ids[] = {
+	{ATK_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, atk_ids);
+
+#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
+
+struct atk_sensor_data {
+	struct list_head list;
+	struct atk_data *data;
+	struct device_attribute label_attr;
+	struct device_attribute input_attr;
+	struct device_attribute limit1_attr;
+	struct device_attribute limit2_attr;
+	char label_attr_name[ATTR_NAME_SIZE];
+	char input_attr_name[ATTR_NAME_SIZE];
+	char limit1_attr_name[ATTR_NAME_SIZE];
+	char limit2_attr_name[ATTR_NAME_SIZE];
+	u64 id;
+	u64 type;
+	u64 limit1;
+	u64 limit2;
+	u64 cached_value;
+	unsigned long last_updated; /* in jiffies */
+	bool is_valid;
+	char const *acpi_name;
+};
+
+/*
+ * Return buffer format:
+ * [0-3] "value" is valid flag
+ * [4-7] value
+ * [8- ] unknown stuff on newer mobos
+ */
+struct atk_acpi_ret_buffer {
+	u32 flags;
+	u32 value;
+	u8 data[];
+};
+
+/* Input buffer used for GITM and SITM methods */
+struct atk_acpi_input_buf {
+	u32 id;
+	u32 param1;
+	u32 param2;
+};
+
+static int atk_add(struct acpi_device *device);
+static int atk_remove(struct acpi_device *device);
+static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
+static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
+static void atk_free_sensors(struct atk_data *data);
+
+static struct acpi_driver atk_driver = {
+	.name	= ATK_HID,
+	.class	= "hwmon",
+	.ids	= atk_ids,
+	.ops	= {
+		.add	= atk_add,
+		.remove	= atk_remove,
+	},
+};
+
+#define input_to_atk_sensor(attr) \
+	container_of(attr, struct atk_sensor_data, input_attr)
+
+#define label_to_atk_sensor(attr) \
+	container_of(attr, struct atk_sensor_data, label_attr)
+
+#define limit1_to_atk_sensor(attr) \
+	container_of(attr, struct atk_sensor_data, limit1_attr)
+
+#define limit2_to_atk_sensor(attr) \
+	container_of(attr, struct atk_sensor_data, limit2_attr)
+
+static ssize_t atk_input_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct atk_sensor_data *s = input_to_atk_sensor(attr);
+	u64 value;
+	int err;
+
+	err = atk_read_value(s, &value);
+	if (err)
+		return err;
+
+	if (s->type == HWMON_TYPE_TEMP)
+		/* ACPI returns decidegree */
+		value *= 100;
+
+	return sprintf(buf, "%llu\n", value);
+}
+
+static ssize_t atk_label_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct atk_sensor_data *s = label_to_atk_sensor(attr);
+
+	return sprintf(buf, "%s\n", s->acpi_name);
+}
+
+static ssize_t atk_limit1_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
+	u64 value = s->limit1;
+
+	if (s->type == HWMON_TYPE_TEMP)
+		value *= 100;
+
+	return sprintf(buf, "%lld\n", value);
+}
+
+static ssize_t atk_limit2_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
+	u64 value = s->limit2;
+
+	if (s->type == HWMON_TYPE_TEMP)
+		value *= 100;
+
+	return sprintf(buf, "%lld\n", value);
+}
+
+static ssize_t atk_name_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "atk0110\n");
+}
+static struct device_attribute atk_name_attr =
+		__ATTR(name, 0444, atk_name_show, NULL);
+
+static void atk_init_attribute(struct device_attribute *attr, char *name,
+		sysfs_show_func show)
+{
+	sysfs_attr_init(&attr->attr);
+	attr->attr.name = name;
+	attr->attr.mode = 0444;
+	attr->show = show;
+	attr->store = NULL;
+}
+
+
+static union acpi_object *atk_get_pack_member(struct atk_data *data,
+						union acpi_object *pack,
+						enum atk_pack_member m)
+{
+	bool old_if = data->old_interface;
+	int offset;
+
+	switch (m) {
+	case HWMON_PACK_FLAGS:
+		offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
+		break;
+	case HWMON_PACK_NAME:
+		offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
+		break;
+	case HWMON_PACK_LIMIT1:
+		offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
+				  _HWMON_NEW_PACK_LIMIT1;
+		break;
+	case HWMON_PACK_LIMIT2:
+		offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
+				  _HWMON_NEW_PACK_LIMIT2;
+		break;
+	case HWMON_PACK_ENABLE:
+		offset = old_if ? _HWMON_OLD_PACK_ENABLE :
+				  _HWMON_NEW_PACK_ENABLE;
+		break;
+	default:
+		return NULL;
+	}
+
+	return &pack->package.elements[offset];
+}
+
+
+/*
+ * New package format is:
+ * - flag (int)
+ *	class - used for de-muxing the request to the correct GITn
+ *	type (volt, temp, fan)
+ *	sensor id |
+ *	sensor id - used for de-muxing the request _inside_ the GITn
+ * - name (str)
+ * - unknown (int)
+ * - unknown (int)
+ * - limit1 (int)
+ * - limit2 (int)
+ * - enable (int)
+ *
+ * The old package has the same format but it's missing the two unknown fields.
+ */
+static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *tmp;
+	bool old_if = data->old_interface;
+	int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
+					   _HWMON_NEW_PACK_SIZE;
+
+	if (obj->type != ACPI_TYPE_PACKAGE) {
+		dev_warn(dev, "Invalid type: %d\n", obj->type);
+		return -EINVAL;
+	}
+
+	if (obj->package.count != expected_size) {
+		dev_warn(dev, "Invalid package size: %d, expected: %d\n",
+				obj->package.count, expected_size);
+		return -EINVAL;
+	}
+
+	tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
+	if (tmp->type != ACPI_TYPE_STRING) {
+		dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	/* Don't check... we don't know what they're useful for anyway */
+#if 0
+	tmp = &obj->package.elements[HWMON_PACK_UNK1];
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	tmp = &obj->package.elements[HWMON_PACK_UNK2];
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
+		return -EINVAL;
+	}
+#endif
+
+	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
+	if (tmp->type != ACPI_TYPE_INTEGER) {
+		dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
+		return -EINVAL;
+	}
+
+	atk_print_sensor(data, obj);
+
+	return 0;
+}
+
+#ifdef DEBUG
+static char const *atk_sensor_type(union acpi_object *flags)
+{
+	u64 type = flags->integer.value & ATK_TYPE_MASK;
+	char const *what;
+
+	switch (type) {
+	case HWMON_TYPE_VOLT:
+		what = "voltage";
+		break;
+	case HWMON_TYPE_TEMP:
+		what = "temperature";
+		break;
+	case HWMON_TYPE_FAN:
+		what = "fan";
+		break;
+	default:
+		what = "unknown";
+		break;
+	}
+
+	return what;
+}
+#endif
+
+static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
+{
+#ifdef DEBUG
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *flags;
+	union acpi_object *name;
+	union acpi_object *limit1;
+	union acpi_object *limit2;
+	union acpi_object *enable;
+	char const *what;
+
+	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
+	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
+	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
+	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
+	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
+
+	what = atk_sensor_type(flags);
+
+	dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
+			flags->integer.value,
+			name->string.pointer,
+			limit1->integer.value, limit2->integer.value,
+			enable->integer.value ? "enabled" : "disabled");
+#endif
+}
+
+static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
+{
+	struct atk_data *data = sensor->data;
+	struct device *dev = &data->acpi_dev->dev;
+	struct acpi_object_list params;
+	union acpi_object id;
+	acpi_status status;
+	acpi_handle method;
+
+	switch (sensor->type) {
+	case HWMON_TYPE_VOLT:
+		method = data->rvlt_handle;
+		break;
+	case HWMON_TYPE_TEMP:
+		method = data->rtmp_handle;
+		break;
+	case HWMON_TYPE_FAN:
+		method = data->rfan_handle;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	id.type = ACPI_TYPE_INTEGER;
+	id.integer.value = sensor->id;
+
+	params.count = 1;
+	params.pointer = &id;
+
+	status = acpi_evaluate_integer(method, NULL, &params, value);
+	if (status != AE_OK) {
+		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
+				acpi_format_exception(status));
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	struct acpi_buffer buf;
+	acpi_status ret;
+	struct acpi_object_list params;
+	union acpi_object id;
+	union acpi_object *pack;
+
+	id.type = ACPI_TYPE_INTEGER;
+	id.integer.value = mux;
+	params.count = 1;
+	params.pointer = &id;
+
+	buf.length = ACPI_ALLOCATE_BUFFER;
+	ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
+	if (ret != AE_OK) {
+		dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
+				acpi_format_exception(ret));
+		return ERR_PTR(-EIO);
+	}
+	pack = buf.pointer;
+	if (pack->type != ACPI_TYPE_PACKAGE) {
+		/* Execution was successful, but the id was not found */
+		ACPI_FREE(pack);
+		return ERR_PTR(-ENOENT);
+	}
+
+	if (pack->package.count < 1) {
+		dev_err(dev, "GGRP[%#x] package is too small\n", mux);
+		ACPI_FREE(pack);
+		return ERR_PTR(-EIO);
+	}
+	return pack;
+}
+
+static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	struct atk_acpi_input_buf buf;
+	union acpi_object tmp;
+	struct acpi_object_list params;
+	struct acpi_buffer ret;
+	union acpi_object *obj;
+	acpi_status status;
+
+	buf.id = id;
+	buf.param1 = 0;
+	buf.param2 = 0;
+
+	tmp.type = ACPI_TYPE_BUFFER;
+	tmp.buffer.pointer = (u8 *)&buf;
+	tmp.buffer.length = sizeof(buf);
+
+	params.count = 1;
+	params.pointer = (void *)&tmp;
+
+	ret.length = ACPI_ALLOCATE_BUFFER;
+	status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
+			&ret, ACPI_TYPE_BUFFER);
+	if (status != AE_OK) {
+		dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
+				acpi_format_exception(status));
+		return ERR_PTR(-EIO);
+	}
+	obj = ret.pointer;
+
+	/* Sanity check */
+	if (obj->buffer.length < 8) {
+		dev_warn(dev, "Unexpected ASBF length: %u\n",
+				obj->buffer.length);
+		ACPI_FREE(obj);
+		return ERR_PTR(-EIO);
+	}
+	return obj;
+}
+
+static union acpi_object *atk_sitm(struct atk_data *data,
+		struct atk_acpi_input_buf *buf)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	struct acpi_object_list params;
+	union acpi_object tmp;
+	struct acpi_buffer ret;
+	union acpi_object *obj;
+	acpi_status status;
+
+	tmp.type = ACPI_TYPE_BUFFER;
+	tmp.buffer.pointer = (u8 *)buf;
+	tmp.buffer.length = sizeof(*buf);
+
+	params.count = 1;
+	params.pointer = &tmp;
+
+	ret.length = ACPI_ALLOCATE_BUFFER;
+	status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
+			&ret, ACPI_TYPE_BUFFER);
+	if (status != AE_OK) {
+		dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
+				acpi_format_exception(status));
+		return ERR_PTR(-EIO);
+	}
+	obj = ret.pointer;
+
+	/* Sanity check */
+	if (obj->buffer.length < 8) {
+		dev_warn(dev, "Unexpected ASBF length: %u\n",
+				obj->buffer.length);
+		ACPI_FREE(obj);
+		return ERR_PTR(-EIO);
+	}
+	return obj;
+}
+
+static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
+{
+	struct atk_data *data = sensor->data;
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *obj;
+	struct atk_acpi_ret_buffer *buf;
+	int err = 0;
+
+	obj = atk_gitm(data, sensor->id);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+	if (buf->flags == 0) {
+		/*
+		 * The reading is not valid, possible causes:
+		 * - sensor failure
+		 * - enumeration was FUBAR (and we didn't notice)
+		 */
+		dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
+		err = -EIO;
+		goto out;
+	}
+
+	*value = buf->value;
+out:
+	ACPI_FREE(obj);
+	return err;
+}
+
+static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
+{
+	int err;
+
+	if (!sensor->is_valid ||
+	    time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
+		if (sensor->data->old_interface)
+			err = atk_read_value_old(sensor, value);
+		else
+			err = atk_read_value_new(sensor, value);
+
+		sensor->is_valid = true;
+		sensor->last_updated = jiffies;
+		sensor->cached_value = *value;
+	} else {
+		*value = sensor->cached_value;
+		err = 0;
+	}
+
+	return err;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int atk_debugfs_gitm_get(void *p, u64 *val)
+{
+	struct atk_data *data = p;
+	union acpi_object *ret;
+	struct atk_acpi_ret_buffer *buf;
+	int err = 0;
+
+	if (!data->read_handle)
+		return -ENODEV;
+
+	if (!data->debugfs.id)
+		return -EINVAL;
+
+	ret = atk_gitm(data, data->debugfs.id);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
+	if (buf->flags)
+		*val = buf->value;
+	else
+		err = -EIO;
+
+	ACPI_FREE(ret);
+	return err;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm,
+			atk_debugfs_gitm_get,
+			NULL,
+			"0x%08llx\n");
+
+static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
+{
+	int ret = 0;
+
+	switch (obj->type) {
+	case ACPI_TYPE_INTEGER:
+		ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
+		break;
+	case ACPI_TYPE_STRING:
+		ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
+		break;
+	}
+
+	return ret;
+}
+
+static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+
+		ret = atk_acpi_print(buf, sz, obj);
+		if (ret >= sz)
+			break;
+		buf += ret;
+		sz -= ret;
+	}
+}
+
+static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
+{
+	struct atk_data *data = inode->i_private;
+	char *buf = NULL;
+	union acpi_object *ret;
+	u8 cls;
+	int i;
+
+	if (!data->enumerate_handle)
+		return -ENODEV;
+	if (!data->debugfs.id)
+		return -EINVAL;
+
+	cls = (data->debugfs.id & 0xff000000) >> 24;
+	ret = atk_ggrp(data, cls);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	for (i = 0; i < ret->package.count; i++) {
+		union acpi_object *pack = &ret->package.elements[i];
+		union acpi_object *id;
+
+		if (pack->type != ACPI_TYPE_PACKAGE)
+			continue;
+		if (!pack->package.count)
+			continue;
+		id = &pack->package.elements[0];
+		if (id->integer.value == data->debugfs.id) {
+			/* Print the package */
+			buf = kzalloc(512, GFP_KERNEL);
+			if (!buf) {
+				ACPI_FREE(ret);
+				return -ENOMEM;
+			}
+			atk_pack_print(buf, 512, pack);
+			break;
+		}
+	}
+	ACPI_FREE(ret);
+
+	if (!buf)
+		return -EINVAL;
+
+	file->private_data = buf;
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
+		size_t count, loff_t *pos)
+{
+	char *str = file->private_data;
+	size_t len = strlen(str);
+
+	return simple_read_from_buffer(buf, count, pos, str, len);
+}
+
+static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations atk_debugfs_ggrp_fops = {
+	.read		= atk_debugfs_ggrp_read,
+	.open		= atk_debugfs_ggrp_open,
+	.release	= atk_debugfs_ggrp_release,
+	.llseek		= no_llseek,
+};
+
+static void atk_debugfs_init(struct atk_data *data)
+{
+	struct dentry *d;
+	struct dentry *f;
+
+	data->debugfs.id = 0;
+
+	d = debugfs_create_dir("asus_atk0110", NULL);
+	if (!d || IS_ERR(d))
+		return;
+
+	f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id);
+	if (!f || IS_ERR(f))
+		goto cleanup;
+
+	f = debugfs_create_file("gitm", S_IRUSR, d, data,
+			&atk_debugfs_gitm);
+	if (!f || IS_ERR(f))
+		goto cleanup;
+
+	f = debugfs_create_file("ggrp", S_IRUSR, d, data,
+			&atk_debugfs_ggrp_fops);
+	if (!f || IS_ERR(f))
+		goto cleanup;
+
+	data->debugfs.root = d;
+
+	return;
+cleanup:
+	debugfs_remove_recursive(d);
+}
+
+static void atk_debugfs_cleanup(struct atk_data *data)
+{
+	debugfs_remove_recursive(data->debugfs.root);
+}
+
+#else /* CONFIG_DEBUG_FS */
+
+static void atk_debugfs_init(struct atk_data *data)
+{
+}
+
+static void atk_debugfs_cleanup(struct atk_data *data)
+{
+}
+#endif
+
+static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *flags;
+	union acpi_object *name;
+	union acpi_object *limit1;
+	union acpi_object *limit2;
+	union acpi_object *enable;
+	struct atk_sensor_data *sensor;
+	char const *base_name;
+	char const *limit1_name;
+	char const *limit2_name;
+	u64 type;
+	int err;
+	int *num;
+	int start;
+
+	if (obj->type != ACPI_TYPE_PACKAGE) {
+		/* wft is this? */
+		dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
+				obj->type);
+		return -EINVAL;
+	}
+
+	err = validate_hwmon_pack(data, obj);
+	if (err)
+		return err;
+
+	/* Ok, we have a valid hwmon package */
+	type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
+	       & ATK_TYPE_MASK;
+
+	switch (type) {
+	case HWMON_TYPE_VOLT:
+		base_name = "in";
+		limit1_name = "min";
+		limit2_name = "max";
+		num = &data->voltage_count;
+		start = 0;
+		break;
+	case HWMON_TYPE_TEMP:
+		base_name = "temp";
+		limit1_name = "max";
+		limit2_name = "crit";
+		num = &data->temperature_count;
+		start = 1;
+		break;
+	case HWMON_TYPE_FAN:
+		base_name = "fan";
+		limit1_name = "min";
+		limit2_name = "max";
+		num = &data->fan_count;
+		start = 1;
+		break;
+	default:
+		dev_warn(dev, "Unknown sensor type: %#llx\n", type);
+		return -EINVAL;
+	}
+
+	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
+	if (!enable->integer.value)
+		/* sensor is disabled */
+		return 0;
+
+	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
+	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
+	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
+	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
+	if (!sensor->acpi_name) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	INIT_LIST_HEAD(&sensor->list);
+	sensor->type = type;
+	sensor->data = data;
+	sensor->id = flags->integer.value;
+	sensor->limit1 = limit1->integer.value;
+	if (data->old_interface)
+		sensor->limit2 = limit2->integer.value;
+	else
+		/* The upper limit is expressed as delta from lower limit */
+		sensor->limit2 = sensor->limit1 + limit2->integer.value;
+
+	snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
+			"%s%d_input", base_name, start + *num);
+	atk_init_attribute(&sensor->input_attr,
+			sensor->input_attr_name,
+			atk_input_show);
+
+	snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
+			"%s%d_label", base_name, start + *num);
+	atk_init_attribute(&sensor->label_attr,
+			sensor->label_attr_name,
+			atk_label_show);
+
+	snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
+			"%s%d_%s", base_name, start + *num, limit1_name);
+	atk_init_attribute(&sensor->limit1_attr,
+			sensor->limit1_attr_name,
+			atk_limit1_show);
+
+	snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
+			"%s%d_%s", base_name, start + *num, limit2_name);
+	atk_init_attribute(&sensor->limit2_attr,
+			sensor->limit2_attr_name,
+			atk_limit2_show);
+
+	list_add(&sensor->list, &data->sensor_list);
+	(*num)++;
+
+	return 1;
+out:
+	kfree(sensor);
+	return err;
+}
+
+static int atk_enumerate_old_hwmon(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	struct acpi_buffer buf;
+	union acpi_object *pack;
+	acpi_status status;
+	int i, ret;
+	int count = 0;
+
+	/* Voltages */
+	buf.length = ACPI_ALLOCATE_BUFFER;
+	status = acpi_evaluate_object_typed(data->atk_handle,
+			METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
+	if (status != AE_OK) {
+		dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
+				acpi_format_exception(status));
+
+		return -ENODEV;
+	}
+
+	pack = buf.pointer;
+	for (i = 1; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+
+		ret = atk_add_sensor(data, obj);
+		if (ret > 0)
+			count++;
+	}
+	ACPI_FREE(buf.pointer);
+
+	/* Temperatures */
+	buf.length = ACPI_ALLOCATE_BUFFER;
+	status = acpi_evaluate_object_typed(data->atk_handle,
+			METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
+	if (status != AE_OK) {
+		dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
+				acpi_format_exception(status));
+
+		ret = -ENODEV;
+		goto cleanup;
+	}
+
+	pack = buf.pointer;
+	for (i = 1; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+
+		ret = atk_add_sensor(data, obj);
+		if (ret > 0)
+			count++;
+	}
+	ACPI_FREE(buf.pointer);
+
+	/* Fans */
+	buf.length = ACPI_ALLOCATE_BUFFER;
+	status = acpi_evaluate_object_typed(data->atk_handle,
+			METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
+	if (status != AE_OK) {
+		dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
+				acpi_format_exception(status));
+
+		ret = -ENODEV;
+		goto cleanup;
+	}
+
+	pack = buf.pointer;
+	for (i = 1; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+
+		ret = atk_add_sensor(data, obj);
+		if (ret > 0)
+			count++;
+	}
+	ACPI_FREE(buf.pointer);
+
+	return count;
+cleanup:
+	atk_free_sensors(data);
+	return ret;
+}
+
+static int atk_ec_present(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *pack;
+	union acpi_object *ec;
+	int ret;
+	int i;
+
+	pack = atk_ggrp(data, ATK_MUX_MGMT);
+	if (IS_ERR(pack)) {
+		if (PTR_ERR(pack) == -ENOENT) {
+			/* The MGMT class does not exists - that's ok */
+			dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
+			return 0;
+		}
+		return PTR_ERR(pack);
+	}
+
+	/* Search the EC */
+	ec = NULL;
+	for (i = 0; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+		union acpi_object *id;
+
+		if (obj->type != ACPI_TYPE_PACKAGE)
+			continue;
+
+		id = &obj->package.elements[0];
+		if (id->type != ACPI_TYPE_INTEGER)
+			continue;
+
+		if (id->integer.value == ATK_EC_ID) {
+			ec = obj;
+			break;
+		}
+	}
+
+	ret = (ec != NULL);
+	if (!ret)
+		/* The system has no EC */
+		dev_dbg(dev, "EC not found\n");
+
+	ACPI_FREE(pack);
+	return ret;
+}
+
+static int atk_ec_enabled(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *obj;
+	struct atk_acpi_ret_buffer *buf;
+	int err;
+
+	obj = atk_gitm(data, ATK_EC_ID);
+	if (IS_ERR(obj)) {
+		dev_err(dev, "Unable to query EC status\n");
+		return PTR_ERR(obj);
+	}
+	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+
+	if (buf->flags == 0) {
+		dev_err(dev, "Unable to query EC status\n");
+		err = -EIO;
+	} else {
+		err = (buf->value != 0);
+		dev_dbg(dev, "EC is %sabled\n",
+				err ? "en" : "dis");
+	}
+
+	ACPI_FREE(obj);
+	return err;
+}
+
+static int atk_ec_ctl(struct atk_data *data, int enable)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *obj;
+	struct atk_acpi_input_buf sitm;
+	struct atk_acpi_ret_buffer *ec_ret;
+	int err = 0;
+
+	sitm.id = ATK_EC_ID;
+	sitm.param1 = enable;
+	sitm.param2 = 0;
+
+	obj = atk_sitm(data, &sitm);
+	if (IS_ERR(obj)) {
+		dev_err(dev, "Failed to %sable the EC\n",
+				enable ? "en" : "dis");
+		return PTR_ERR(obj);
+	}
+	ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+	if (ec_ret->flags == 0) {
+		dev_err(dev, "Failed to %sable the EC\n",
+				enable ? "en" : "dis");
+		err = -EIO;
+	} else {
+		dev_info(dev, "EC %sabled\n",
+				enable ? "en" : "dis");
+	}
+
+	ACPI_FREE(obj);
+	return err;
+}
+
+static int atk_enumerate_new_hwmon(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	union acpi_object *pack;
+	int err;
+	int i;
+
+	err = atk_ec_present(data);
+	if (err < 0)
+		return err;
+	if (err) {
+		err = atk_ec_enabled(data);
+		if (err < 0)
+			return err;
+		/* If the EC was disabled we will disable it again on unload */
+		data->disable_ec = err;
+
+		err = atk_ec_ctl(data, 1);
+		if (err) {
+			data->disable_ec = false;
+			return err;
+		}
+	}
+
+	dev_dbg(dev, "Enumerating hwmon sensors\n");
+
+	pack = atk_ggrp(data, ATK_MUX_HWMON);
+	if (IS_ERR(pack))
+		return PTR_ERR(pack);
+
+	for (i = 0; i < pack->package.count; i++) {
+		union acpi_object *obj = &pack->package.elements[i];
+
+		atk_add_sensor(data, obj);
+	}
+
+	err = data->voltage_count + data->temperature_count + data->fan_count;
+
+	ACPI_FREE(pack);
+	return err;
+}
+
+static int atk_create_files(struct atk_data *data)
+{
+	struct atk_sensor_data *s;
+	int err;
+
+	list_for_each_entry(s, &data->sensor_list, list) {
+		err = device_create_file(data->hwmon_dev, &s->input_attr);
+		if (err)
+			return err;
+		err = device_create_file(data->hwmon_dev, &s->label_attr);
+		if (err)
+			return err;
+		err = device_create_file(data->hwmon_dev, &s->limit1_attr);
+		if (err)
+			return err;
+		err = device_create_file(data->hwmon_dev, &s->limit2_attr);
+		if (err)
+			return err;
+	}
+
+	err = device_create_file(data->hwmon_dev, &atk_name_attr);
+
+	return err;
+}
+
+static void atk_remove_files(struct atk_data *data)
+{
+	struct atk_sensor_data *s;
+
+	list_for_each_entry(s, &data->sensor_list, list) {
+		device_remove_file(data->hwmon_dev, &s->input_attr);
+		device_remove_file(data->hwmon_dev, &s->label_attr);
+		device_remove_file(data->hwmon_dev, &s->limit1_attr);
+		device_remove_file(data->hwmon_dev, &s->limit2_attr);
+	}
+	device_remove_file(data->hwmon_dev, &atk_name_attr);
+}
+
+static void atk_free_sensors(struct atk_data *data)
+{
+	struct list_head *head = &data->sensor_list;
+	struct atk_sensor_data *s, *tmp;
+
+	list_for_each_entry_safe(s, tmp, head, list) {
+		kfree(s->acpi_name);
+		kfree(s);
+	}
+}
+
+static int atk_register_hwmon(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	int err;
+
+	dev_dbg(dev, "registering hwmon device\n");
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev))
+		return PTR_ERR(data->hwmon_dev);
+
+	dev_dbg(dev, "populating sysfs directory\n");
+	err = atk_create_files(data);
+	if (err)
+		goto remove;
+
+	return 0;
+remove:
+	/* Cleanup the registered files */
+	atk_remove_files(data);
+	hwmon_device_unregister(data->hwmon_dev);
+	return err;
+}
+
+static int atk_probe_if(struct atk_data *data)
+{
+	struct device *dev = &data->acpi_dev->dev;
+	acpi_handle ret;
+	acpi_status status;
+	int err = 0;
+
+	/* RTMP: read temperature */
+	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
+	if (ACPI_SUCCESS(status))
+		data->rtmp_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
+				acpi_format_exception(status));
+
+	/* RVLT: read voltage */
+	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
+	if (ACPI_SUCCESS(status))
+		data->rvlt_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
+				acpi_format_exception(status));
+
+	/* RFAN: read fan status */
+	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
+	if (ACPI_SUCCESS(status))
+		data->rfan_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
+				acpi_format_exception(status));
+
+	/* Enumeration */
+	status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
+	if (ACPI_SUCCESS(status))
+		data->enumerate_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
+				acpi_format_exception(status));
+
+	/* De-multiplexer (read) */
+	status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
+	if (ACPI_SUCCESS(status))
+		data->read_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
+				acpi_format_exception(status));
+
+	/* De-multiplexer (write) */
+	status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
+	if (ACPI_SUCCESS(status))
+		data->write_handle = ret;
+	else
+		dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
+				 acpi_format_exception(status));
+
+	/*
+	 * Check for hwmon methods: first check "old" style methods; note that
+	 * both may be present: in this case we stick to the old interface;
+	 * analysis of multiple DSDTs indicates that when both interfaces
+	 * are present the new one (GGRP/GITM) is not functional.
+	 */
+	if (new_if)
+		dev_info(dev, "Overriding interface detection\n");
+	if (data->rtmp_handle &&
+			data->rvlt_handle && data->rfan_handle && !new_if)
+		data->old_interface = true;
+	else if (data->enumerate_handle && data->read_handle &&
+			data->write_handle)
+		data->old_interface = false;
+	else
+		err = -ENODEV;
+
+	return err;
+}
+
+static int atk_add(struct acpi_device *device)
+{
+	acpi_status ret;
+	int err;
+	struct acpi_buffer buf;
+	union acpi_object *obj;
+	struct atk_data *data;
+
+	dev_dbg(&device->dev, "adding...\n");
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->acpi_dev = device;
+	data->atk_handle = device->handle;
+	INIT_LIST_HEAD(&data->sensor_list);
+	data->disable_ec = false;
+
+	buf.length = ACPI_ALLOCATE_BUFFER;
+	ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
+			&buf, ACPI_TYPE_PACKAGE);
+	if (ret != AE_OK) {
+		dev_dbg(&device->dev, "atk: method MBIF not found\n");
+	} else {
+		obj = buf.pointer;
+		if (obj->package.count >= 2) {
+			union acpi_object *id = &obj->package.elements[1];
+			if (id->type == ACPI_TYPE_STRING)
+				dev_dbg(&device->dev, "board ID = %s\n",
+					id->string.pointer);
+		}
+		ACPI_FREE(buf.pointer);
+	}
+
+	err = atk_probe_if(data);
+	if (err) {
+		dev_err(&device->dev, "No usable hwmon interface detected\n");
+		goto out;
+	}
+
+	if (data->old_interface) {
+		dev_dbg(&device->dev, "Using old hwmon interface\n");
+		err = atk_enumerate_old_hwmon(data);
+	} else {
+		dev_dbg(&device->dev, "Using new hwmon interface\n");
+		err = atk_enumerate_new_hwmon(data);
+	}
+	if (err < 0)
+		goto out;
+	if (err == 0) {
+		dev_info(&device->dev,
+			 "No usable sensor detected, bailing out\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = atk_register_hwmon(data);
+	if (err)
+		goto cleanup;
+
+	atk_debugfs_init(data);
+
+	device->driver_data = data;
+	return 0;
+cleanup:
+	atk_free_sensors(data);
+out:
+	if (data->disable_ec)
+		atk_ec_ctl(data, 0);
+	kfree(data);
+	return err;
+}
+
+static int atk_remove(struct acpi_device *device)
+{
+	struct atk_data *data = device->driver_data;
+	dev_dbg(&device->dev, "removing...\n");
+
+	device->driver_data = NULL;
+
+	atk_debugfs_cleanup(data);
+
+	atk_remove_files(data);
+	atk_free_sensors(data);
+	hwmon_device_unregister(data->hwmon_dev);
+
+	if (data->disable_ec) {
+		if (atk_ec_ctl(data, 0))
+			dev_err(&device->dev, "Failed to disable EC\n");
+	}
+
+	kfree(data);
+
+	return 0;
+}
+
+static int __init atk0110_init(void)
+{
+	int ret;
+
+	/* Make sure it's safe to access the device through ACPI */
+	if (!acpi_resources_are_enforced()) {
+		pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
+		return -EBUSY;
+	}
+
+	if (dmi_check_system(atk_force_new_if))
+		new_if = true;
+
+	ret = acpi_bus_register_driver(&atk_driver);
+	if (ret)
+		pr_info("acpi_bus_register_driver failed: %d\n", ret);
+
+	return ret;
+}
+
+static void __exit atk0110_exit(void)
+{
+	acpi_bus_unregister_driver(&atk_driver);
+}
+
+module_init(atk0110_init);
+module_exit(atk0110_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
new file mode 100644
index 0000000..f2f2f2f
--- /dev/null
+++ b/drivers/hwmon/atxp1.c
@@ -0,0 +1,307 @@
+/*
+ * atxp1.c - kernel module for setting CPU VID and general purpose
+ *	     I/Os using the Attansic ATXP1 chip.
+ *
+ * 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.
+ *
+ * The ATXP1 can reside on I2C addresses 0x37 or 0x4e. The chip is
+ * not auto-detected by the driver and must be instantiated explicitly.
+ * See Documentation/i2c/instantiating-devices for more information.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
+MODULE_VERSION("0.6.3");
+MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
+
+#define ATXP1_VID	0x00
+#define ATXP1_CVID	0x01
+#define ATXP1_GPIO1	0x06
+#define ATXP1_GPIO2	0x0a
+#define ATXP1_VIDENA	0x20
+#define ATXP1_VIDMASK	0x1f
+#define ATXP1_GPIO1MASK	0x0f
+
+struct atxp1_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	unsigned long last_updated;
+	u8 valid;
+	struct {
+		u8 vid;		/* VID output register */
+		u8 cpu_vid; /* VID input from CPU */
+		u8 gpio1;   /* General purpose I/O register 1 */
+		u8 gpio2;   /* General purpose I/O register 2 */
+	} reg;
+	u8 vrm;			/* Detected CPU VRM */
+};
+
+static struct atxp1_data *atxp1_update_device(struct device *dev)
+{
+	struct atxp1_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+
+		/* Update local register data */
+		data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
+		data->reg.cpu_vid = i2c_smbus_read_byte_data(client,
+							     ATXP1_CVID);
+		data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
+		data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
+
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* sys file functions for cpu0_vid */
+static ssize_t atxp1_showvcore(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int size;
+	struct atxp1_data *data;
+
+	data = atxp1_update_device(dev);
+
+	size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK,
+						 data->vrm));
+
+	return size;
+}
+
+static ssize_t atxp1_storevcore(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct atxp1_data *data = atxp1_update_device(dev);
+	struct i2c_client *client = data->client;
+	int vid, cvid;
+	unsigned long vcore;
+	int err;
+
+	err = kstrtoul(buf, 10, &vcore);
+	if (err)
+		return err;
+
+	vcore /= 25;
+	vcore *= 25;
+
+	/* Calculate VID */
+	vid = vid_to_reg(vcore, data->vrm);
+	if (vid < 0) {
+		dev_err(dev, "VID calculation failed.\n");
+		return vid;
+	}
+
+	/*
+	 * If output enabled, use control register value.
+	 * Otherwise original CPU VID
+	 */
+	if (data->reg.vid & ATXP1_VIDENA)
+		cvid = data->reg.vid & ATXP1_VIDMASK;
+	else
+		cvid = data->reg.cpu_vid;
+
+	/* Nothing changed, aborting */
+	if (vid == cvid)
+		return count;
+
+	dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid);
+
+	/* Write every 25 mV step to increase stability */
+	if (cvid > vid) {
+		for (; cvid >= vid; cvid--)
+			i2c_smbus_write_byte_data(client,
+						ATXP1_VID, cvid | ATXP1_VIDENA);
+	} else {
+		for (; cvid <= vid; cvid++)
+			i2c_smbus_write_byte_data(client,
+						ATXP1_VID, cvid | ATXP1_VIDENA);
+	}
+
+	data->valid = 0;
+
+	return count;
+}
+
+/*
+ * CPU core reference voltage
+ * unit: millivolt
+ */
+static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore,
+		   atxp1_storevcore);
+
+/* sys file functions for GPIO1 */
+static ssize_t atxp1_showgpio1(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int size;
+	struct atxp1_data *data;
+
+	data = atxp1_update_device(dev);
+
+	size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
+
+	return size;
+}
+
+static ssize_t atxp1_storegpio1(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct atxp1_data *data = atxp1_update_device(dev);
+	struct i2c_client *client = data->client;
+	unsigned long value;
+	int err;
+
+	err = kstrtoul(buf, 16, &value);
+	if (err)
+		return err;
+
+	value &= ATXP1_GPIO1MASK;
+
+	if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
+		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
+
+		i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
+
+		data->valid = 0;
+	}
+
+	return count;
+}
+
+/*
+ * GPIO1 data register
+ * unit: Four bit as hex (e.g. 0x0f)
+ */
+static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
+
+/* sys file functions for GPIO2 */
+static ssize_t atxp1_showgpio2(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int size;
+	struct atxp1_data *data;
+
+	data = atxp1_update_device(dev);
+
+	size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
+
+	return size;
+}
+
+static ssize_t atxp1_storegpio2(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct atxp1_data *data = atxp1_update_device(dev);
+	struct i2c_client *client = data->client;
+	unsigned long value;
+	int err;
+
+	err = kstrtoul(buf, 16, &value);
+	if (err)
+		return err;
+	value &= 0xff;
+
+	if (value != data->reg.gpio2) {
+		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
+
+		i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
+
+		data->valid = 0;
+	}
+
+	return count;
+}
+
+/*
+ * GPIO2 data register
+ * unit: Eight bit as hex (e.g. 0xff)
+ */
+static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
+
+static struct attribute *atxp1_attrs[] = {
+	&dev_attr_gpio1.attr,
+	&dev_attr_gpio2.attr,
+	&dev_attr_cpu0_vid.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(atxp1);
+
+static int atxp1_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct atxp1_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct atxp1_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* Get VRM */
+	data->vrm = vid_which_vrm();
+	if (data->vrm != 90 && data->vrm != 91) {
+		dev_err(dev, "atxp1: Not supporting VRM %d.%d\n",
+			data->vrm / 10, data->vrm % 10);
+		return -ENODEV;
+	}
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   atxp1_groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(dev, "Using VRM: %d.%d\n", data->vrm / 10, data->vrm % 10);
+
+	return 0;
+};
+
+static const struct i2c_device_id atxp1_id[] = {
+	{ "atxp1", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, atxp1_id);
+
+static struct i2c_driver atxp1_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "atxp1",
+	},
+	.probe		= atxp1_probe,
+	.id_table	= atxp1_id,
+};
+
+module_i2c_driver(atxp1_driver);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
new file mode 100644
index 0000000..6a27eb2
--- /dev/null
+++ b/drivers/hwmon/coretemp.c
@@ -0,0 +1,858 @@
+/*
+ * coretemp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Inspired from many hwmon drivers
+ *
+ * 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 <linux/smp.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/cpu_device_id.h>
+
+#define DRVNAME	"coretemp"
+
+/*
+ * force_tjmax only matters when TjMax can't be read from the CPU itself.
+ * When set, it replaces the driver's suboptimal heuristic.
+ */
+static int force_tjmax;
+module_param_named(tjmax, force_tjmax, int, 0444);
+MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+
+#define BASE_SYSFS_ATTR_NO	2	/* Sysfs Base attr no for coretemp */
+#define NUM_REAL_CORES		128	/* Number of Real cores per cpu */
+#define CORETEMP_NAME_LENGTH	19	/* String Length of attrs */
+#define MAX_CORE_ATTRS		4	/* Maximum no of basic attrs */
+#define TOTAL_ATTRS		(MAX_CORE_ATTRS + 1)
+#define MAX_CORE_DATA		(NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
+
+#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)
+
+#ifdef CONFIG_SMP
+#define for_each_sibling(i, cpu) \
+	for_each_cpu(i, topology_sibling_cpumask(cpu))
+#else
+#define for_each_sibling(i, cpu)	for (i = 0; false; )
+#endif
+
+/*
+ * 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.
+ * @attr_size:  Total number of pre-core attrs displayed in the sysfs.
+ * @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.
+ */
+struct temp_data {
+	int temp;
+	int ttarget;
+	int tjmax;
+	unsigned long last_updated;
+	unsigned int cpu;
+	u32 cpu_core_id;
+	u32 status_reg;
+	int attr_size;
+	bool is_pkg_data;
+	bool valid;
+	struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
+	char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
+	struct attribute *attrs[TOTAL_ATTRS + 1];
+	struct attribute_group attr_group;
+	struct mutex update_lock;
+};
+
+/* 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;
+};
+
+struct pdev_entry {
+	struct list_head list;
+	struct platform_device *pdev;
+	u16 phys_proc_id;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static ssize_t show_label(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);
+	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)
+{
+	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];
+
+	mutex_lock(&tdata->update_lock);
+
+	/* 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);
+		/*
+		 * Ignore the valid bit. In all observed cases the register
+		 * value is either low or zero if the valid bit is 0.
+		 * Return it instead of reporting an error which doesn't
+		 * really help at all.
+		 */
+		tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
+		tdata->valid = 1;
+		tdata->last_updated = jiffies;
+	}
+
+	mutex_unlock(&tdata->update_lock);
+	return sprintf(buf, "%d\n", tdata->temp);
+}
+
+struct tjmax_pci {
+	unsigned int device;
+	int tjmax;
+};
+
+static const struct tjmax_pci tjmax_pci_table[] = {
+	{ 0x0708, 110000 },	/* CE41x0 (Sodaville ) */
+	{ 0x0c72, 102000 },	/* Atom S1240 (Centerton) */
+	{ 0x0c73, 95000 },	/* Atom S1220 (Centerton) */
+	{ 0x0c75, 95000 },	/* Atom S1260 (Centerton) */
+};
+
+struct tjmax {
+	char const *id;
+	int tjmax;
+};
+
+static const struct tjmax tjmax_table[] = {
+	{ "CPU  230", 100000 },		/* Model 0x1c, stepping 2	*/
+	{ "CPU  330", 125000 },		/* Model 0x1c, stepping 2	*/
+};
+
+struct tjmax_model {
+	u8 model;
+	u8 mask;
+	int tjmax;
+};
+
+#define ANY 0xff
+
+static const struct tjmax_model tjmax_model_table[] = {
+	{ 0x1c, 10, 100000 },	/* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
+	{ 0x1c, ANY, 90000 },	/* Z5xx, N2xx, possibly others
+				 * Note: Also matches 230 and 330,
+				 * which are covered by tjmax_table
+				 */
+	{ 0x26, ANY, 90000 },	/* Atom Tunnel Creek (Exx), Lincroft (Z6xx)
+				 * Note: TjMax for E6xxT is 110C, but CPU type
+				 * is undetectable by software
+				 */
+	{ 0x27, ANY, 90000 },	/* Atom Medfield (Z2460) */
+	{ 0x35, ANY, 90000 },	/* Atom Clover Trail/Cloverview (Z27x0) */
+	{ 0x36, ANY, 100000 },	/* Atom Cedar Trail/Cedarview (N2xxx, D2xxx)
+				 * Also matches S12x0 (stepping 9), covered by
+				 * PCI table
+				 */
+};
+
+static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+{
+	/* The 100C is default for both mobile and non mobile CPUs */
+
+	int tjmax = 100000;
+	int tjmax_ee = 85000;
+	int usemsr_ee = 1;
+	int err;
+	u32 eax, edx;
+	int i;
+	struct pci_dev *host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
+
+	/*
+	 * Explicit tjmax table entries override heuristics.
+	 * First try PCI host bridge IDs, followed by model ID strings
+	 * and model/stepping information.
+	 */
+	if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) {
+		for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) {
+			if (host_bridge->device == tjmax_pci_table[i].device)
+				return tjmax_pci_table[i].tjmax;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {
+		if (strstr(c->x86_model_id, tjmax_table[i].id))
+			return tjmax_table[i].tjmax;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
+		const struct tjmax_model *tm = &tjmax_model_table[i];
+		if (c->x86_model == tm->model &&
+		    (tm->mask == ANY || c->x86_mask == tm->mask))
+			return tm->tjmax;
+	}
+
+	/* Early chips have no MSR for TjMax */
+
+	if (c->x86_model == 0xf && c->x86_mask < 4)
+		usemsr_ee = 0;
+
+	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
+		 */
+		err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+				 "Unable to access MSR 0x17, assuming desktop"
+				 " 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
+			 */
+			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
+				 */
+				tjmax_ee = 90000;
+				tjmax = 105000;
+			}
+		}
+	}
+
+	if (usemsr_ee) {
+		err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+				 "Unable to access MSR 0xEE, for Tjmax, left"
+				 " at default\n");
+		} else if (eax & 0x40000000) {
+			tjmax = tjmax_ee;
+		}
+	} 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 bool cpu_has_tjmax(struct cpuinfo_x86 *c)
+{
+	u8 model = c->x86_model;
+
+	return model > 0xe &&
+	       model != 0x1c &&
+	       model != 0x26 &&
+	       model != 0x27 &&
+	       model != 0x35 &&
+	       model != 0x36;
+}
+
+static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+{
+	int err;
+	u32 eax, edx;
+	u32 val;
+
+	/*
+	 * 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) {
+		if (cpu_has_tjmax(c))
+			dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
+	} else {
+		val = (eax >> 16) & 0xff;
+		/*
+		 * If the TjMax is not plausible, an assumption
+		 * will be used
+		 */
+		if (val) {
+			dev_dbg(dev, "TjMax is %d degrees C\n", val);
+			return val * 1000;
+		}
+	}
+
+	if (force_tjmax) {
+		dev_notice(dev, "TjMax forced to %d degrees C by user\n",
+			   force_tjmax);
+		return force_tjmax * 1000;
+	}
+
+	/*
+	 * An assumption is made for early CPUs and unreadable MSR.
+	 * NOTE: the calculated value may not be correct.
+	 */
+	return adjust_tjmax(c, id, dev);
+}
+
+static int create_core_attrs(struct temp_data *tdata, struct device *dev,
+			     int attr_no)
+{
+	int i;
+	static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
+			struct device_attribute *devattr, char *buf) = {
+			show_label, show_crit_alarm, show_temp, show_tjmax,
+			show_ttarget };
+	static const char *const suffixes[TOTAL_ATTRS] = {
+		"label", "crit_alarm", "input", "crit", "max"
+	};
+
+	for (i = 0; i < tdata->attr_size; i++) {
+		snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH,
+			 "temp%d_%s", attr_no, suffixes[i]);
+		sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
+		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].index = attr_no;
+		tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
+	}
+	tdata->attr_group.attrs = tdata->attrs;
+	return sysfs_create_group(&dev->kobj, &tdata->attr_group);
+}
+
+
+static int chk_ucode_version(unsigned int cpu)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+	/*
+	 * 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 && c->microcode < 0x39) {
+		pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+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);
+	tdata->attr_size = MAX_CORE_ATTRS;
+	mutex_init(&tdata->update_lock);
+	return tdata;
+}
+
+static int create_core_data(struct platform_device *pdev, unsigned int cpu,
+			    int pkg_flag)
+{
+	struct temp_data *tdata;
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	u32 eax, edx;
+	int err, attr_no;
+
+	/*
+	 * 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 (attr_no > MAX_CORE_DATA - 1)
+		return -ERANGE;
+
+	/*
+	 * Provide a single set of attributes for all HT siblings of a core
+	 * to avoid duplicate sensors (the processor ID and core ID of all
+	 * HT siblings of a core are the same).
+	 * Skip if a HT sibling of this core is already registered.
+	 * This is not an error.
+	 */
+	if (pdata->core_data[attr_no] != NULL)
+		return 0;
+
+	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 */
+	tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+
+	/*
+	 * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
+	 * The target temperature is available on older CPUs but not in this
+	 * register. Atoms don't have the register at all.
+	 */
+	if (c->x86_model > 0xe && c->x86_model != 0x1c) {
+		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
+					&eax, &edx);
+		if (!err) {
+			tdata->ttarget
+			  = tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
+			tdata->attr_size++;
+		}
+	}
+
+	pdata->core_data[attr_no] = tdata;
+
+	/* Create sysfs interfaces */
+	err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
+	if (err)
+		goto exit_free;
+
+	return 0;
+exit_free:
+	pdata->core_data[attr_no] = NULL;
+	kfree(tdata);
+	return err;
+}
+
+static void coretemp_add_core(unsigned int cpu, int pkg_flag)
+{
+	struct platform_device *pdev = coretemp_get_pdev(cpu);
+	int err;
+
+	if (!pdev)
+		return;
+
+	err = create_core_data(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,
+				 int indx)
+{
+	struct temp_data *tdata = pdata->core_data[indx];
+
+	/* Remove the sysfs attributes */
+	sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
+
+	kfree(pdata->core_data[indx]);
+	pdata->core_data[indx] = NULL;
+}
+
+static int coretemp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct platform_data *pdata;
+
+	/* Initialize the per-package data structures */
+	pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->phys_proc_id = pdev->id;
+	platform_set_drvdata(pdev, pdata);
+
+	pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
+								  pdata, NULL);
+	return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
+}
+
+static int coretemp_remove(struct platform_device *pdev)
+{
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = MAX_CORE_DATA - 1; i >= 0; --i)
+		if (pdata->core_data[i])
+			coretemp_remove_core(pdata, i);
+
+	return 0;
+}
+
+static struct platform_driver coretemp_driver = {
+	.driver = {
+		.name = DRVNAME,
+	},
+	.probe = coretemp_probe,
+	.remove = coretemp_remove,
+};
+
+static int coretemp_device_add(unsigned int cpu)
+{
+	int err;
+	struct platform_device *pdev;
+	struct pdev_entry *pdev_entry;
+
+	mutex_lock(&pdev_list_mutex);
+
+	pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(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;
+	}
+
+	pdev_entry->pdev = pdev;
+	pdev_entry->phys_proc_id = pdev->id;
+
+	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 coretemp_device_remove(unsigned int cpu)
+{
+	struct pdev_entry *p, *n;
+	u16 phys_proc_id = TO_PHYS_ID(cpu);
+
+	mutex_lock(&pdev_list_mutex);
+	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);
+		kfree(p);
+	}
+	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 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_DTHERM))
+		return;
+
+	if (!pdev) {
+		/* Check the microcode version of the CPU */
+		if (chk_ucode_version(cpu))
+			return;
+
+		/*
+		 * 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 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);
+
+	/* The core id is too big, just return */
+	if (indx > MAX_CORE_DATA - 1)
+		return;
+
+	if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
+		coretemp_remove_core(pdata, indx);
+
+	/*
+	 * If a HT sibling of a core is taken offline, but another HT sibling
+	 * of the same core is still online, register the alternate sibling.
+	 * This ensures that exactly one set of attributes is provided as long
+	 * as at least one HT sibling of a core is online.
+	 */
+	for_each_sibling(i, cpu) {
+		if (i != cpu) {
+			get_core_online(i);
+			/*
+			 * Display temperature sensor data for one HT sibling
+			 * per core only, so abort the loop after one such
+			 * sibling has been found.
+			 */
+			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 coretemp_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:
+		get_core_online(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		put_core_offline(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block coretemp_cpu_notifier __refdata = {
+	.notifier_call = coretemp_cpu_callback,
+};
+
+static const struct x86_cpu_id __initconst coretemp_ids[] = {
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
+
+static int __init coretemp_init(void)
+{
+	int i, 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 (!x86_match_cpu(coretemp_ids))
+		return -ENODEV;
+
+	err = platform_driver_register(&coretemp_driver);
+	if (err)
+		goto exit;
+
+	cpu_notifier_register_begin();
+	for_each_online_cpu(i)
+		get_core_online(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
+	if (list_empty(&pdev_list)) {
+		cpu_notifier_register_done();
+		err = -ENODEV;
+		goto exit_driver_unreg;
+	}
+#endif
+
+	__register_hotcpu_notifier(&coretemp_cpu_notifier);
+	cpu_notifier_register_done();
+	return 0;
+
+#ifndef CONFIG_HOTPLUG_CPU
+exit_driver_unreg:
+	platform_driver_unregister(&coretemp_driver);
+#endif
+exit:
+	return err;
+}
+
+static void __exit coretemp_exit(void)
+{
+	struct pdev_entry *p, *n;
+
+	cpu_notifier_register_begin();
+	__unregister_hotcpu_notifier(&coretemp_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);
+	cpu_notifier_register_done();
+	platform_driver_unregister(&coretemp_driver);
+}
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
+MODULE_DESCRIPTION("Intel Core temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(coretemp_init)
+module_exit(coretemp_exit)
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
new file mode 100644
index 0000000..c9832bf
--- /dev/null
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -0,0 +1,293 @@
+/*
+ * HWMON Driver for Dialog DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ *  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.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+struct da9052_hwmon {
+	struct da9052	*da9052;
+	struct mutex	hwmon_lock;
+};
+
+static const char * const input_names[] = {
+	[DA9052_ADC_VDDOUT]	=	"VDDOUT",
+	[DA9052_ADC_ICH]	=	"CHARGING CURRENT",
+	[DA9052_ADC_TBAT]	=	"BATTERY TEMP",
+	[DA9052_ADC_VBAT]	=	"BATTERY VOLTAGE",
+	[DA9052_ADC_IN4]	=	"ADC IN4",
+	[DA9052_ADC_IN5]	=	"ADC IN5",
+	[DA9052_ADC_IN6]	=	"ADC IN6",
+	[DA9052_ADC_TJUNC]	=	"BATTERY JUNCTION TEMP",
+	[DA9052_ADC_VBBAT]	=	"BACK-UP BATTERY VOLTAGE",
+};
+
+/* Conversion function for VDDOUT and VBAT */
+static inline int volt_reg_to_mv(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
+}
+
+/* Conversion function for ADC channels 4, 5 and 6 */
+static inline int input_reg_to_mv(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 2500, 1023);
+}
+
+/* Conversion function for VBBAT */
+static inline int vbbat_reg_to_mv(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 5000, 1023);
+}
+
+static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
+{
+	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+				 DA9052_ADCCONT_AUTOVDDEN,
+				 DA9052_ADCCONT_AUTOVDDEN);
+}
+
+static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
+{
+	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+				 DA9052_ADCCONT_AUTOVDDEN, 0);
+}
+
+static ssize_t da9052_read_vddout(struct device *dev,
+				  struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret, vdd;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	ret = da9052_enable_vddout_channel(hwmon->da9052);
+	if (ret < 0)
+		goto hwmon_err;
+
+	vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
+	if (vdd < 0) {
+		ret = vdd;
+		goto hwmon_err_release;
+	}
+
+	ret = da9052_disable_vddout_channel(hwmon->da9052);
+	if (ret < 0)
+		goto hwmon_err;
+
+	mutex_unlock(&hwmon->hwmon_lock);
+	return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
+
+hwmon_err_release:
+	da9052_disable_vddout_channel(hwmon->da9052);
+hwmon_err:
+	mutex_unlock(&hwmon->hwmon_lock);
+	return ret;
+}
+
+static ssize_t da9052_read_ich(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
+	if (ret < 0)
+		return ret;
+
+	/* Equivalent to 3.9mA/bit in register ICHG_AV */
+	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
+}
+
+static ssize_t da9052_read_tbat(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
+}
+
+static ssize_t da9052_read_vbat(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
+}
+
+static ssize_t da9052_read_misc_channel(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(devattr)->index;
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, channel);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", input_reg_to_mv(ret));
+}
+
+static ssize_t da9052_read_tjunc(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int tjunc;
+	int toffset;
+
+	tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
+	if (tjunc < 0)
+		return tjunc;
+
+	toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
+	if (toffset < 0)
+		return toffset;
+
+	/*
+	 * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
+	 * T_OFFSET is a trim value used to improve accuracy of the result
+	 */
+	return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
+}
+
+static ssize_t da9052_read_vbbat(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n",
+		       input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9052_read_vddout, NULL,
+			  DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9052_read_vbat, NULL,
+			  DA9052_ADC_VBAT);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VBAT);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN4);
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN5);
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN6);
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN6);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, da9052_read_vbbat, NULL,
+			  DA9052_ADC_VBBAT);
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VBBAT);
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, da9052_read_ich, NULL,
+			  DA9052_ADC_ICH);
+static SENSOR_DEVICE_ATTR(curr1_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_ICH);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, da9052_read_tbat, NULL,
+			  DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, da9052_read_tjunc, NULL,
+			  DA9052_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_TJUNC);
+
+static struct attribute *da9052_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_label.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_label.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in9_label.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_label.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(da9052);
+
+static int da9052_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9052_hwmon *hwmon;
+	struct device *hwmon_dev;
+
+	hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	mutex_init(&hwmon->hwmon_lock);
+	hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
+							   hwmon,
+							   da9052_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver da9052_hwmon_driver = {
+	.probe = da9052_hwmon_probe,
+	.driver = {
+		.name = "da9052-hwmon",
+	},
+};
+
+module_platform_driver(da9052_hwmon_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 HWMON driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-hwmon");
diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c
new file mode 100644
index 0000000..f6e159c
--- /dev/null
+++ b/drivers/hwmon/da9055-hwmon.c
@@ -0,0 +1,297 @@
+/*
+ * HWMON Driver for Dialog DA9055
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ *  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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+#define DA9055_ADCIN_DIV	102
+#define DA9055_VSYS_DIV	85
+
+#define DA9055_ADC_VSYS	0
+#define DA9055_ADC_ADCIN1	1
+#define DA9055_ADC_ADCIN2	2
+#define DA9055_ADC_ADCIN3	3
+#define DA9055_ADC_TJUNC	4
+
+struct da9055_hwmon {
+	struct da9055	*da9055;
+	struct mutex	hwmon_lock;
+	struct mutex	irq_lock;
+	struct completion done;
+};
+
+static const char * const input_names[] = {
+	[DA9055_ADC_VSYS]	= "VSYS",
+	[DA9055_ADC_ADCIN1]	= "ADC IN1",
+	[DA9055_ADC_ADCIN2]	= "ADC IN2",
+	[DA9055_ADC_ADCIN3]	= "ADC IN3",
+	[DA9055_ADC_TJUNC]	= "CHIP TEMP",
+};
+
+static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = {
+	[DA9055_ADC_VSYS]	= DA9055_ADC_MUX_VSYS,
+	[DA9055_ADC_ADCIN1]	= DA9055_ADC_MUX_ADCIN1,
+	[DA9055_ADC_ADCIN2]	= DA9055_ADC_MUX_ADCIN2,
+	[DA9055_ADC_ADCIN3]	= DA9055_ADC_MUX_ADCIN3,
+	[DA9055_ADC_TJUNC]	= DA9055_ADC_MUX_T_SENSE,
+};
+
+static int da9055_adc_manual_read(struct da9055_hwmon *hwmon,
+					unsigned char channel)
+{
+	int ret;
+	unsigned short calc_data;
+	unsigned short data;
+	unsigned char mux_sel;
+	struct da9055 *da9055 = hwmon->da9055;
+
+	if (channel > DA9055_ADC_TJUNC)
+		return -EINVAL;
+
+	mutex_lock(&hwmon->irq_lock);
+
+	/* Selects desired MUX for manual conversion */
+	mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV;
+
+	ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel);
+	if (ret < 0)
+		goto err;
+
+	/* Wait for an interrupt */
+	if (!wait_for_completion_timeout(&hwmon->done,
+					msecs_to_jiffies(500))) {
+		dev_err(da9055->dev,
+			"timeout waiting for ADC conversion interrupt\n");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H);
+	if (ret < 0)
+		goto err;
+
+	calc_data = (unsigned short)ret;
+	data = calc_data << 2;
+
+	ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L);
+	if (ret < 0)
+		goto err;
+
+	calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK);
+	data |= calc_data;
+
+	ret = data;
+
+err:
+	mutex_unlock(&hwmon->irq_lock);
+	return ret;
+}
+
+static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
+{
+	struct da9055_hwmon *hwmon = irq_data;
+
+	complete(&hwmon->done);
+
+	return IRQ_HANDLED;
+}
+
+/* Conversion function for VSYS and ADCINx */
+static inline int volt_reg_to_mv(int value, int channel)
+{
+	if (channel == DA9055_ADC_VSYS)
+		return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
+	else
+		return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV);
+}
+
+static int da9055_enable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+	return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel,
+				1 << channel);
+
+}
+
+static int da9055_disable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+	return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0);
+}
+
+static ssize_t da9055_read_auto_ch(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret, adc;
+	int channel = to_sensor_dev_attr(devattr)->index;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	ret = da9055_enable_auto_mode(hwmon->da9055, channel);
+	if (ret < 0)
+		goto hwmon_err;
+
+	usleep_range(10000, 10500);
+
+	adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel);
+	if (adc < 0) {
+		ret = adc;
+		goto hwmon_err_release;
+	}
+
+	ret = da9055_disable_auto_mode(hwmon->da9055, channel);
+	if (ret < 0)
+		goto hwmon_err;
+
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel));
+
+hwmon_err_release:
+	da9055_disable_auto_mode(hwmon->da9055, channel);
+hwmon_err:
+	mutex_unlock(&hwmon->hwmon_lock);
+	return ret;
+}
+
+static ssize_t da9055_read_tjunc(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+	int tjunc;
+	int toffset;
+
+	tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC);
+	if (tjunc < 0)
+		return tjunc;
+
+	toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET);
+	if (toffset < 0)
+		return toffset;
+
+	/*
+	 * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
+	 * T_OFFSET is a trim value used to improve accuracy of the result
+	 */
+	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset)
+							+ 3076332, 10000));
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n",
+		       input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL,
+			  DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
+			  DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL,
+			  DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL,
+			  DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL,
+			  DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL,
+			  DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL,
+			  DA9055_ADC_ADCIN3);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
+			  DA9055_ADC_ADCIN3);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL,
+			  DA9055_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
+			  DA9055_ADC_TJUNC);
+
+static struct attribute *da9055_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(da9055);
+
+static int da9055_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9055_hwmon *hwmon;
+	struct device *hwmon_dev;
+	int hwmon_irq, ret;
+
+	hwmon = devm_kzalloc(dev, sizeof(struct da9055_hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	mutex_init(&hwmon->hwmon_lock);
+	mutex_init(&hwmon->irq_lock);
+
+	init_completion(&hwmon->done);
+	hwmon->da9055 = dev_get_drvdata(pdev->dev.parent);
+
+	hwmon_irq = platform_get_irq_byname(pdev, "HWMON");
+	if (hwmon_irq < 0)
+		return hwmon_irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq,
+					NULL, da9055_auxadc_irq,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					"adc-irq", hwmon);
+	if (ret != 0) {
+		dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n",
+			ret);
+		return ret;
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9055",
+							   hwmon,
+							   da9055_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver da9055_hwmon_driver = {
+	.probe = da9055_hwmon_probe,
+	.driver = {
+		.name = "da9055-hwmon",
+	},
+};
+
+module_platform_driver(da9055_hwmon_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 HWMON driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-hwmon");
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
new file mode 100644
index 0000000..a9356a3
--- /dev/null
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -0,0 +1,1088 @@
+/*
+ * dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
+ *
+ * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
+ *
+ * Hwmon integration:
+ * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2013, 2014  Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2014, 2015  Pali Rohár <pali.rohar@gmail.com>
+ *
+ * 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, 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
+#include <linux/capability.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+
+#include <linux/i8k.h>
+
+#define I8K_SMM_FN_STATUS	0x0025
+#define I8K_SMM_POWER_STATUS	0x0069
+#define I8K_SMM_SET_FAN		0x01a3
+#define I8K_SMM_GET_FAN		0x00a3
+#define I8K_SMM_GET_SPEED	0x02a3
+#define I8K_SMM_GET_FAN_TYPE	0x03a3
+#define I8K_SMM_GET_NOM_SPEED	0x04a3
+#define I8K_SMM_GET_TEMP	0x10a3
+#define I8K_SMM_GET_TEMP_TYPE	0x11a3
+#define I8K_SMM_GET_DELL_SIG1	0xfea3
+#define I8K_SMM_GET_DELL_SIG2	0xffa3
+
+#define I8K_FAN_MULT		30
+#define I8K_FAN_MAX_RPM		30000
+#define I8K_MAX_TEMP		127
+
+#define I8K_FN_NONE		0x00
+#define I8K_FN_UP		0x01
+#define I8K_FN_DOWN		0x02
+#define I8K_FN_MUTE		0x04
+#define I8K_FN_MASK		0x07
+#define I8K_FN_SHIFT		8
+
+#define I8K_POWER_AC		0x05
+#define I8K_POWER_BATTERY	0x01
+
+static DEFINE_MUTEX(i8k_mutex);
+static char bios_version[4];
+static char bios_machineid[16];
+static struct device *i8k_hwmon_dev;
+static u32 i8k_hwmon_flags;
+static uint i8k_fan_mult = I8K_FAN_MULT;
+static uint i8k_pwm_mult;
+static uint i8k_fan_max = I8K_FAN_HIGH;
+static bool disallow_fan_type_call;
+
+#define I8K_HWMON_HAVE_TEMP1	(1 << 0)
+#define I8K_HWMON_HAVE_TEMP2	(1 << 1)
+#define I8K_HWMON_HAVE_TEMP3	(1 << 2)
+#define I8K_HWMON_HAVE_TEMP4	(1 << 3)
+#define I8K_HWMON_HAVE_FAN1	(1 << 4)
+#define I8K_HWMON_HAVE_FAN2	(1 << 5)
+
+MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
+MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_DESCRIPTION("Dell laptop SMM BIOS hwmon driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i8k");
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+
+static bool ignore_dmi;
+module_param(ignore_dmi, bool, 0);
+MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
+
+#if IS_ENABLED(CONFIG_I8K)
+static bool restricted = true;
+module_param(restricted, bool, 0);
+MODULE_PARM_DESC(restricted, "Restrict fan control and serial number to CAP_SYS_ADMIN (default: 1)");
+
+static bool power_status;
+module_param(power_status, bool, 0600);
+MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k (default: 0)");
+#endif
+
+static uint fan_mult;
+module_param(fan_mult, uint, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)");
+
+static uint fan_max;
+module_param(fan_max, uint, 0);
+MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)");
+
+struct smm_regs {
+	unsigned int eax;
+	unsigned int ebx __packed;
+	unsigned int ecx __packed;
+	unsigned int edx __packed;
+	unsigned int esi __packed;
+	unsigned int edi __packed;
+};
+
+static inline const char *i8k_get_dmi_data(int field)
+{
+	const char *dmi_data = dmi_get_system_info(field);
+
+	return dmi_data && *dmi_data ? dmi_data : "?";
+}
+
+/*
+ * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
+ */
+static int i8k_smm(struct smm_regs *regs)
+{
+	int rc;
+	int eax = regs->eax;
+	cpumask_var_t old_mask;
+
+	/* SMM requires CPU 0 */
+	if (!alloc_cpumask_var(&old_mask, GFP_KERNEL))
+		return -ENOMEM;
+	cpumask_copy(old_mask, &current->cpus_allowed);
+	rc = set_cpus_allowed_ptr(current, cpumask_of(0));
+	if (rc)
+		goto out;
+	if (smp_processor_id() != 0) {
+		rc = -EBUSY;
+		goto out;
+	}
+
+#if defined(CONFIG_X86_64)
+	asm volatile("pushq %%rax\n\t"
+		"movl 0(%%rax),%%edx\n\t"
+		"pushq %%rdx\n\t"
+		"movl 4(%%rax),%%ebx\n\t"
+		"movl 8(%%rax),%%ecx\n\t"
+		"movl 12(%%rax),%%edx\n\t"
+		"movl 16(%%rax),%%esi\n\t"
+		"movl 20(%%rax),%%edi\n\t"
+		"popq %%rax\n\t"
+		"out %%al,$0xb2\n\t"
+		"out %%al,$0x84\n\t"
+		"xchgq %%rax,(%%rsp)\n\t"
+		"movl %%ebx,4(%%rax)\n\t"
+		"movl %%ecx,8(%%rax)\n\t"
+		"movl %%edx,12(%%rax)\n\t"
+		"movl %%esi,16(%%rax)\n\t"
+		"movl %%edi,20(%%rax)\n\t"
+		"popq %%rdx\n\t"
+		"movl %%edx,0(%%rax)\n\t"
+		"pushfq\n\t"
+		"popq %%rax\n\t"
+		"andl $1,%%eax\n"
+		: "=a"(rc)
+		:    "a"(regs)
+		:    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+#else
+	asm volatile("pushl %%eax\n\t"
+	    "movl 0(%%eax),%%edx\n\t"
+	    "push %%edx\n\t"
+	    "movl 4(%%eax),%%ebx\n\t"
+	    "movl 8(%%eax),%%ecx\n\t"
+	    "movl 12(%%eax),%%edx\n\t"
+	    "movl 16(%%eax),%%esi\n\t"
+	    "movl 20(%%eax),%%edi\n\t"
+	    "popl %%eax\n\t"
+	    "out %%al,$0xb2\n\t"
+	    "out %%al,$0x84\n\t"
+	    "xchgl %%eax,(%%esp)\n\t"
+	    "movl %%ebx,4(%%eax)\n\t"
+	    "movl %%ecx,8(%%eax)\n\t"
+	    "movl %%edx,12(%%eax)\n\t"
+	    "movl %%esi,16(%%eax)\n\t"
+	    "movl %%edi,20(%%eax)\n\t"
+	    "popl %%edx\n\t"
+	    "movl %%edx,0(%%eax)\n\t"
+	    "lahf\n\t"
+	    "shrl $8,%%eax\n\t"
+	    "andl $1,%%eax\n"
+	    : "=a"(rc)
+	    :    "a"(regs)
+	    :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+#endif
+	if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
+		rc = -EINVAL;
+
+out:
+	set_cpus_allowed_ptr(current, old_mask);
+	free_cpumask_var(old_mask);
+	return rc;
+}
+
+/*
+ * Read the fan status.
+ */
+static int i8k_get_fan_status(int fan)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
+
+	regs.ebx = fan & 0xff;
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+/*
+ * Read the fan speed in RPM.
+ */
+static int i8k_get_fan_speed(int fan)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
+
+	regs.ebx = fan & 0xff;
+	return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
+/*
+ * Read the fan type.
+ */
+static int _i8k_get_fan_type(int fan)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
+
+	if (disallow_fan_type_call)
+		return -EINVAL;
+
+	regs.ebx = fan & 0xff;
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+static int i8k_get_fan_type(int fan)
+{
+	/* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */
+	static int types[2] = { INT_MIN, INT_MIN };
+
+	if (types[fan] == INT_MIN)
+		types[fan] = _i8k_get_fan_type(fan);
+
+	return types[fan];
+}
+
+/*
+ * Read the fan nominal rpm for specific fan speed.
+ */
+static int i8k_get_fan_nominal_speed(int fan, int speed)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
+
+	regs.ebx = (fan & 0xff) | (speed << 8);
+	return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
+/*
+ * Set the fan speed (off, low, high). Returns the new fan status.
+ */
+static int i8k_set_fan(int fan, int speed)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
+
+	speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
+	regs.ebx = (fan & 0xff) | (speed << 8);
+
+	return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
+}
+
+static int i8k_get_temp_type(int sensor)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };
+
+	regs.ebx = sensor & 0xff;
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+/*
+ * Read the cpu temperature.
+ */
+static int _i8k_get_temp(int sensor)
+{
+	struct smm_regs regs = {
+		.eax = I8K_SMM_GET_TEMP,
+		.ebx = sensor & 0xff,
+	};
+
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+static int i8k_get_temp(int sensor)
+{
+	int temp = _i8k_get_temp(sensor);
+
+	/*
+	 * Sometimes the temperature sensor returns 0x99, which is out of range.
+	 * In this case we retry (once) before returning an error.
+	 # 1003655137 00000058 00005a4b
+	 # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
+	 # 1003655139 00000054 00005c52
+	 */
+	if (temp == 0x99) {
+		msleep(100);
+		temp = _i8k_get_temp(sensor);
+	}
+	/*
+	 * Return -ENODATA for all invalid temperatures.
+	 *
+	 * Known instances are the 0x99 value as seen above as well as
+	 * 0xc1 (193), which may be returned when trying to read the GPU
+	 * temperature if the system supports a GPU and it is currently
+	 * turned off.
+	 */
+	if (temp > I8K_MAX_TEMP)
+		return -ENODATA;
+
+	return temp;
+}
+
+static int i8k_get_dell_signature(int req_fn)
+{
+	struct smm_regs regs = { .eax = req_fn, };
+	int rc;
+
+	rc = i8k_smm(&regs);
+	if (rc < 0)
+		return rc;
+
+	return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
+}
+
+#if IS_ENABLED(CONFIG_I8K)
+
+/*
+ * Read the Fn key status.
+ */
+static int i8k_get_fn_status(void)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
+	int rc;
+
+	rc = i8k_smm(&regs);
+	if (rc < 0)
+		return rc;
+
+	switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
+	case I8K_FN_UP:
+		return I8K_VOL_UP;
+	case I8K_FN_DOWN:
+		return I8K_VOL_DOWN;
+	case I8K_FN_MUTE:
+		return I8K_VOL_MUTE;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Read the power status.
+ */
+static int i8k_get_power_status(void)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
+	int rc;
+
+	rc = i8k_smm(&regs);
+	if (rc < 0)
+		return rc;
+
+	return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
+}
+
+/*
+ * Procfs interface
+ */
+
+static int
+i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	int val = 0;
+	int speed;
+	unsigned char buff[16];
+	int __user *argp = (int __user *)arg;
+
+	if (!argp)
+		return -EINVAL;
+
+	switch (cmd) {
+	case I8K_BIOS_VERSION:
+		val = (bios_version[0] << 16) |
+				(bios_version[1] << 8) | bios_version[2];
+		break;
+
+	case I8K_MACHINE_ID:
+		if (restricted && !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		memset(buff, 0, sizeof(buff));
+		strlcpy(buff, bios_machineid, sizeof(buff));
+		break;
+
+	case I8K_FN_STATUS:
+		val = i8k_get_fn_status();
+		break;
+
+	case I8K_POWER_STATUS:
+		val = i8k_get_power_status();
+		break;
+
+	case I8K_GET_TEMP:
+		val = i8k_get_temp(0);
+		break;
+
+	case I8K_GET_SPEED:
+		if (copy_from_user(&val, argp, sizeof(int)))
+			return -EFAULT;
+
+		val = i8k_get_fan_speed(val);
+		break;
+
+	case I8K_GET_FAN:
+		if (copy_from_user(&val, argp, sizeof(int)))
+			return -EFAULT;
+
+		val = i8k_get_fan_status(val);
+		break;
+
+	case I8K_SET_FAN:
+		if (restricted && !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&val, argp, sizeof(int)))
+			return -EFAULT;
+
+		if (copy_from_user(&speed, argp + 1, sizeof(int)))
+			return -EFAULT;
+
+		val = i8k_set_fan(val, speed);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (val < 0)
+		return val;
+
+	switch (cmd) {
+	case I8K_BIOS_VERSION:
+		if (copy_to_user(argp, &val, 4))
+			return -EFAULT;
+
+		break;
+	case I8K_MACHINE_ID:
+		if (copy_to_user(argp, buff, 16))
+			return -EFAULT;
+
+		break;
+	default:
+		if (copy_to_user(argp, &val, sizeof(int)))
+			return -EFAULT;
+
+		break;
+	}
+
+	return 0;
+}
+
+static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	long ret;
+
+	mutex_lock(&i8k_mutex);
+	ret = i8k_ioctl_unlocked(fp, cmd, arg);
+	mutex_unlock(&i8k_mutex);
+
+	return ret;
+}
+
+/*
+ * Print the information for /proc/i8k.
+ */
+static int i8k_proc_show(struct seq_file *seq, void *offset)
+{
+	int fn_key, cpu_temp, ac_power;
+	int left_fan, right_fan, left_speed, right_speed;
+
+	cpu_temp	= i8k_get_temp(0);			/* 11100 µs */
+	left_fan	= i8k_get_fan_status(I8K_FAN_LEFT);	/*   580 µs */
+	right_fan	= i8k_get_fan_status(I8K_FAN_RIGHT);	/*   580 µs */
+	left_speed	= i8k_get_fan_speed(I8K_FAN_LEFT);	/*   580 µs */
+	right_speed	= i8k_get_fan_speed(I8K_FAN_RIGHT);	/*   580 µs */
+	fn_key		= i8k_get_fn_status();			/*   750 µs */
+	if (power_status)
+		ac_power = i8k_get_power_status();		/* 14700 µs */
+	else
+		ac_power = -1;
+
+	/*
+	 * Info:
+	 *
+	 * 1)  Format version (this will change if format changes)
+	 * 2)  BIOS version
+	 * 3)  BIOS machine ID
+	 * 4)  Cpu temperature
+	 * 5)  Left fan status
+	 * 6)  Right fan status
+	 * 7)  Left fan speed
+	 * 8)  Right fan speed
+	 * 9)  AC power
+	 * 10) Fn Key status
+	 */
+	seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
+		   I8K_PROC_FMT,
+		   bios_version,
+		   (restricted && !capable(CAP_SYS_ADMIN)) ? "-1" : bios_machineid,
+		   cpu_temp,
+		   left_fan, right_fan, left_speed, right_speed,
+		   ac_power, fn_key);
+
+	return 0;
+}
+
+static int i8k_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, i8k_proc_show, NULL);
+}
+
+static const struct file_operations i8k_fops = {
+	.owner		= THIS_MODULE,
+	.open		= i8k_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.unlocked_ioctl	= i8k_ioctl,
+};
+
+static void __init i8k_init_procfs(void)
+{
+	/* Register the proc entry */
+	proc_create("i8k", 0, NULL, &i8k_fops);
+}
+
+static void __exit i8k_exit_procfs(void)
+{
+	remove_proc_entry("i8k", NULL);
+}
+
+#else
+
+static inline void __init i8k_init_procfs(void)
+{
+}
+
+static inline void __exit i8k_exit_procfs(void)
+{
+}
+
+#endif
+
+/*
+ * Hwmon interface
+ */
+
+static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
+					 struct device_attribute *devattr,
+					 char *buf)
+{
+	static const char * const labels[] = {
+		"CPU",
+		"GPU",
+		"SODIMM",
+		"Other",
+		"Ambient",
+		"Other",
+	};
+	int index = to_sensor_dev_attr(devattr)->index;
+	int type;
+
+	type = i8k_get_temp_type(index);
+	if (type < 0)
+		return type;
+	if (type >= ARRAY_SIZE(labels))
+		type = ARRAY_SIZE(labels) - 1;
+	return sprintf(buf, "%s\n", labels[type]);
+}
+
+static ssize_t i8k_hwmon_show_temp(struct device *dev,
+				   struct device_attribute *devattr,
+				   char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	int temp;
+
+	temp = i8k_get_temp(index);
+	if (temp < 0)
+		return temp;
+	return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	static const char * const labels[] = {
+		"Processor Fan",
+		"Motherboard Fan",
+		"Video Fan",
+		"Power Supply Fan",
+		"Chipset Fan",
+		"Other Fan",
+	};
+	int index = to_sensor_dev_attr(devattr)->index;
+	bool dock = false;
+	int type;
+
+	type = i8k_get_fan_type(index);
+	if (type < 0)
+		return type;
+
+	if (type & 0x10) {
+		dock = true;
+		type &= 0x0F;
+	}
+
+	if (type >= ARRAY_SIZE(labels))
+		type = (ARRAY_SIZE(labels) - 1);
+
+	return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
+}
+
+static ssize_t i8k_hwmon_show_fan(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	int fan_speed;
+
+	fan_speed = i8k_get_fan_speed(index);
+	if (fan_speed < 0)
+		return fan_speed;
+	return sprintf(buf, "%d\n", fan_speed);
+}
+
+static ssize_t i8k_hwmon_show_pwm(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	int status;
+
+	status = i8k_get_fan_status(index);
+	if (status < 0)
+		return -EIO;
+	return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
+}
+
+static ssize_t i8k_hwmon_set_pwm(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);
+
+	mutex_lock(&i8k_mutex);
+	err = i8k_set_fan(index, val);
+	mutex_unlock(&i8k_mutex);
+
+	return err < 0 ? -EIO : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+			  0);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
+			  i8k_hwmon_set_pwm, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+			  1);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+			  1);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
+			  i8k_hwmon_set_pwm, 1);
+
+static struct attribute *i8k_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,	/* 0 */
+	&sensor_dev_attr_temp1_label.dev_attr.attr,	/* 1 */
+	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 2 */
+	&sensor_dev_attr_temp2_label.dev_attr.attr,	/* 3 */
+	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 4 */
+	&sensor_dev_attr_temp3_label.dev_attr.attr,	/* 5 */
+	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 6 */
+	&sensor_dev_attr_temp4_label.dev_attr.attr,	/* 7 */
+	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 8 */
+	&sensor_dev_attr_fan1_label.dev_attr.attr,	/* 9 */
+	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 10 */
+	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 11 */
+	&sensor_dev_attr_fan2_label.dev_attr.attr,	/* 12 */
+	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 13 */
+	NULL
+};
+
+static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
+			      int index)
+{
+	if (disallow_fan_type_call &&
+	    (index == 9 || index == 12))
+		return 0;
+	if (index >= 0 && index <= 1 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
+		return 0;
+	if (index >= 2 && index <= 3 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
+		return 0;
+	if (index >= 4 && index <= 5 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
+		return 0;
+	if (index >= 6 && index <= 7 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+		return 0;
+	if (index >= 8 && index <= 10 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
+		return 0;
+	if (index >= 11 && index <= 13 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
+		return 0;
+
+	return attr->mode;
+}
+
+static const struct attribute_group i8k_group = {
+	.attrs = i8k_attrs,
+	.is_visible = i8k_is_visible,
+};
+__ATTRIBUTE_GROUPS(i8k);
+
+static int __init i8k_init_hwmon(void)
+{
+	int err;
+
+	i8k_hwmon_flags = 0;
+
+	/* CPU temperature attributes, if temperature type is OK */
+	err = i8k_get_temp_type(0);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;
+	/* check for additional temperature sensors */
+	err = i8k_get_temp_type(1);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;
+	err = i8k_get_temp_type(2);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;
+	err = i8k_get_temp_type(3);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
+
+	/* First fan attributes, if fan status or type is OK */
+	err = i8k_get_fan_status(0);
+	if (err < 0)
+		err = i8k_get_fan_type(0);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
+
+	/* Second fan attributes, if fan status or type is OK */
+	err = i8k_get_fan_status(1);
+	if (err < 0)
+		err = i8k_get_fan_type(1);
+	if (err >= 0)
+		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
+
+	i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell_smm",
+							  NULL, i8k_groups);
+	if (IS_ERR(i8k_hwmon_dev)) {
+		err = PTR_ERR(i8k_hwmon_dev);
+		i8k_hwmon_dev = NULL;
+		pr_err("hwmon registration failed (%d)\n", err);
+		return err;
+	}
+	return 0;
+}
+
+struct i8k_config_data {
+	uint fan_mult;
+	uint fan_max;
+};
+
+enum i8k_configs {
+	DELL_LATITUDE_D520,
+	DELL_PRECISION_490,
+	DELL_STUDIO,
+	DELL_XPS,
+};
+
+static const struct i8k_config_data i8k_config_data[] = {
+	[DELL_LATITUDE_D520] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_TURBO,
+	},
+	[DELL_PRECISION_490] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_TURBO,
+	},
+	[DELL_STUDIO] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_HIGH,
+	},
+	[DELL_XPS] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_HIGH,
+	},
+};
+
+static struct dmi_system_id i8k_dmi_table[] __initdata = {
+	{
+		.ident = "Dell Inspiron",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+		},
+	},
+	{
+		.ident = "Dell Latitude",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+		},
+	},
+	{
+		.ident = "Dell Inspiron 2",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+		},
+	},
+	{
+		.ident = "Dell Latitude D520",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
+	},
+	{
+		.ident = "Dell Latitude 2",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+		},
+	},
+	{	/* UK Inspiron 6400  */
+		.ident = "Dell Inspiron 3",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
+		},
+	},
+	{
+		.ident = "Dell Inspiron 3",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MP061"),
+		},
+	},
+	{
+		.ident = "Dell Precision 490",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME,
+				  "Precision WorkStation 490"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_PRECISION_490],
+	},
+	{
+		.ident = "Dell Precision",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Precision"),
+		},
+	},
+	{
+		.ident = "Dell Vostro",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),
+		},
+	},
+	{
+		.ident = "Dell XPS421",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
+		},
+	},
+	{
+		.ident = "Dell Studio",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
+	},
+	{
+		.ident = "Dell XPS 13",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_XPS],
+	},
+	{
+		.ident = "Dell XPS M140",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_XPS],
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
+
+/*
+ * On some machines once I8K_SMM_GET_FAN_TYPE is issued then CPU fan speed
+ * randomly going up and down due to bug in Dell SMM or BIOS. Here is blacklist
+ * of affected Dell machines for which we disallow I8K_SMM_GET_FAN_TYPE call.
+ * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=100121
+ */
+static struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initdata = {
+	{
+		.ident = "Dell Studio XPS 8000",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8000"),
+		},
+	},
+	{
+		.ident = "Dell Studio XPS 8100",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
+		},
+	},
+	{
+		.ident = "Dell Inspiron 580",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 580 "),
+		},
+	},
+	{ }
+};
+
+/*
+ * Probe for the presence of a supported laptop.
+ */
+static int __init i8k_probe(void)
+{
+	const struct dmi_system_id *id;
+	int fan, ret;
+
+	/*
+	 * Get DMI information
+	 */
+	if (!dmi_check_system(i8k_dmi_table)) {
+		if (!ignore_dmi && !force)
+			return -ENODEV;
+
+		pr_info("not running on a supported Dell system.\n");
+		pr_info("vendor=%s, model=%s, version=%s\n",
+			i8k_get_dmi_data(DMI_SYS_VENDOR),
+			i8k_get_dmi_data(DMI_PRODUCT_NAME),
+			i8k_get_dmi_data(DMI_BIOS_VERSION));
+	}
+
+	if (dmi_check_system(i8k_blacklist_fan_type_dmi_table))
+		disallow_fan_type_call = true;
+
+	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),
+		sizeof(bios_version));
+	strlcpy(bios_machineid, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
+		sizeof(bios_machineid));
+
+	/*
+	 * Get SMM Dell signature
+	 */
+	if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
+	    i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
+		pr_err("unable to get SMM Dell signature\n");
+		if (!force)
+			return -ENODEV;
+	}
+
+	/*
+	 * Set fan multiplier and maximal fan speed from dmi config
+	 * Values specified in module parameters override values from dmi
+	 */
+	id = dmi_first_match(i8k_dmi_table);
+	if (id && id->driver_data) {
+		const struct i8k_config_data *conf = id->driver_data;
+		if (!fan_mult && conf->fan_mult)
+			fan_mult = conf->fan_mult;
+		if (!fan_max && conf->fan_max)
+			fan_max = conf->fan_max;
+	}
+
+	i8k_fan_max = fan_max ? : I8K_FAN_HIGH;	/* Must not be 0 */
+	i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
+
+	if (!fan_mult) {
+		/*
+		 * Autodetect fan multiplier based on nominal rpm
+		 * If fan reports rpm value too high then set multiplier to 1
+		 */
+		for (fan = 0; fan < 2; ++fan) {
+			ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);
+			if (ret < 0)
+				continue;
+			if (ret > I8K_FAN_MAX_RPM)
+				i8k_fan_mult = 1;
+			break;
+		}
+	} else {
+		/* Fan multiplier was specified in module param or in dmi */
+		i8k_fan_mult = fan_mult;
+	}
+
+	return 0;
+}
+
+static int __init i8k_init(void)
+{
+	int err;
+
+	/* Are we running on an supported laptop? */
+	if (i8k_probe())
+		return -ENODEV;
+
+	err = i8k_init_hwmon();
+	if (err)
+		return err;
+
+	i8k_init_procfs();
+	return 0;
+}
+
+static void __exit i8k_exit(void)
+{
+	hwmon_device_unregister(i8k_hwmon_dev);
+	i8k_exit_procfs();
+}
+
+module_init(i8k_init);
+module_exit(i8k_exit);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
new file mode 100644
index 0000000..8763c4a
--- /dev/null
+++ b/drivers/hwmon/dme1737.c
@@ -0,0 +1,2797 @@
+/*
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
+ *             and SCH5127 Super-I/O chips integrated hardware monitoring
+ *             features.
+ * Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
+ * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
+ * if a SCH311x or SCH5127 chip is found. Both types of chips have very
+ * similar hardware monitoring capabilities but differ in the way they can be
+ * accessed.
+ *
+ * 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.
+ */
+
+#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/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* ISA device, if found */
+static struct platform_device *pdev;
+
+/* Module load parameters */
+static bool force_start;
+module_param(force_start, bool, 0);
+MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static bool probe_all_addr;
+module_param(probe_all_addr, bool, 0);
+MODULE_PARM_DESC(probe_all_addr,
+		 "Include probing of non-standard LPC addresses");
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+
+enum chips { dme1737, sch5027, sch311x, sch5127 };
+
+#define	DO_REPORT "Please report to the driver maintainer."
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows:
+ *
+ * Voltages                          Temperatures
+ * --------                          ------------
+ * in0   +5VTR (+5V stdby)           temp1   Remote diode 1
+ * in1   Vccp  (proc core)           temp2   Internal temp
+ * in2   VCC   (internal +3.3V)      temp3   Remote diode 2
+ * in3   +5V
+ * in4   +12V
+ * in5   VTR   (+3.3V stby)
+ * in6   Vbat
+ * in7   Vtrip (sch5127 only)
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-7 (ix) */
+#define DME1737_REG_IN(ix)		((ix) < 5 ? 0x20 + (ix) : \
+					 (ix) < 7 ? 0x94 + (ix) : \
+						    0x1f)
+#define DME1737_REG_IN_MIN(ix)		((ix) < 5 ? 0x44 + (ix) * 2 \
+						  : 0x91 + (ix) * 2)
+#define DME1737_REG_IN_MAX(ix)		((ix) < 5 ? 0x45 + (ix) * 2 \
+						  : 0x92 + (ix) * 2)
+
+/* Temperatures (temp) numbered 0-2 (ix) */
+#define DME1737_REG_TEMP(ix)		(0x25 + (ix))
+#define DME1737_REG_TEMP_MIN(ix)	(0x4e + (ix) * 2)
+#define DME1737_REG_TEMP_MAX(ix)	(0x4f + (ix) * 2)
+#define DME1737_REG_TEMP_OFFSET(ix)	((ix) == 0 ? 0x1f \
+						   : 0x1c + (ix))
+
+/*
+ * Voltage and temperature LSBs
+ * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
+ *    IN_TEMP_LSB(0) = [in5, in6]
+ *    IN_TEMP_LSB(1) = [temp3, temp1]
+ *    IN_TEMP_LSB(2) = [in4, temp2]
+ *    IN_TEMP_LSB(3) = [in3, in0]
+ *    IN_TEMP_LSB(4) = [in2, in1]
+ *    IN_TEMP_LSB(5) = [res, in7]
+ */
+#define DME1737_REG_IN_TEMP_LSB(ix)	(0x84 + (ix))
+static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4};
+static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
+static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
+
+/* Fans numbered 0-5 (ix) */
+#define DME1737_REG_FAN(ix)		((ix) < 4 ? 0x28 + (ix) * 2 \
+						  : 0xa1 + (ix) * 2)
+#define DME1737_REG_FAN_MIN(ix)		((ix) < 4 ? 0x54 + (ix) * 2 \
+						  : 0xa5 + (ix) * 2)
+#define DME1737_REG_FAN_OPT(ix)		((ix) < 4 ? 0x90 + (ix) \
+						  : 0xb2 + (ix))
+#define DME1737_REG_FAN_MAX(ix)		(0xb4 + (ix)) /* only for fan[4-5] */
+
+/* PWMs numbered 0-2, 4-5 (ix) */
+#define DME1737_REG_PWM(ix)		((ix) < 3 ? 0x30 + (ix) \
+						  : 0xa1 + (ix))
+#define DME1737_REG_PWM_CONFIG(ix)	(0x5c + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_MIN(ix)		(0x64 + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_FREQ(ix)	((ix) < 3 ? 0x5f + (ix) \
+						  : 0xa3 + (ix))
+/*
+ * The layout of the ramp rate registers is different from the other pwm
+ * registers. The bits for the 3 PWMs are stored in 2 registers:
+ *    PWM_RR(0) = [OFF3, OFF2,  OFF1,  RES,   RR1E, RR1-2, RR1-1, RR1-0]
+ *    PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0]
+ */
+#define DME1737_REG_PWM_RR(ix)		(0x62 + (ix)) /* only for pwm[0-2] */
+
+/* Thermal zones 0-2 */
+#define DME1737_REG_ZONE_LOW(ix)	(0x67 + (ix))
+#define DME1737_REG_ZONE_ABS(ix)	(0x6a + (ix))
+/*
+ * The layout of the hysteresis registers is different from the other zone
+ * registers. The bits for the 3 zones are stored in 2 registers:
+ *    ZONE_HYST(0) = [H1-3,  H1-2,  H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    ZONE_HYST(1) = [H3-3,  H3-2,  H3-1, H3-0, RES,  RES,  RES,  RES]
+ */
+#define DME1737_REG_ZONE_HYST(ix)	(0x6d + (ix))
+
+/*
+ * Alarm registers and bit mapping
+ * The 3 8-bit alarm registers will be concatenated to a single 32-bit
+ * alarm value [0, ALARM3, ALARM2, ALARM1].
+ */
+#define DME1737_REG_ALARM1		0x41
+#define DME1737_REG_ALARM2		0x42
+#define DME1737_REG_ALARM3		0x83
+static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17, 18};
+static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
+static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
+
+/* Miscellaneous registers */
+#define DME1737_REG_DEVICE		0x3d
+#define DME1737_REG_COMPANY		0x3e
+#define DME1737_REG_VERSTEP		0x3f
+#define DME1737_REG_CONFIG		0x40
+#define DME1737_REG_CONFIG2		0x7f
+#define DME1737_REG_VID			0x43
+#define DME1737_REG_TACH_PWM		0x81
+
+/* ---------------------------------------------------------------------
+ * Misc defines
+ * --------------------------------------------------------------------- */
+
+/* Chip identification */
+#define DME1737_COMPANY_SMSC	0x5c
+#define DME1737_VERSTEP		0x88
+#define DME1737_VERSTEP_MASK	0xf8
+#define SCH311X_DEVICE		0x8c
+#define SCH5027_VERSTEP		0x69
+#define SCH5127_DEVICE		0x8e
+
+/* Device ID values (global configuration register index 0x20) */
+#define DME1737_ID_1	0x77
+#define DME1737_ID_2	0x78
+#define SCH3112_ID	0x7c
+#define SCH3114_ID	0x7d
+#define SCH3116_ID	0x7f
+#define SCH5027_ID	0x89
+#define SCH5127_ID	0x86
+
+/* Length of ISA address segment */
+#define DME1737_EXTENT	2
+
+/* chip-dependent features */
+#define HAS_TEMP_OFFSET		(1 << 0)		/* bit 0 */
+#define HAS_VID			(1 << 1)		/* bit 1 */
+#define HAS_ZONE3		(1 << 2)		/* bit 2 */
+#define HAS_ZONE_HYST		(1 << 3)		/* bit 3 */
+#define HAS_PWM_MIN		(1 << 4)		/* bit 4 */
+#define HAS_FAN(ix)		(1 << ((ix) + 5))	/* bits 5-10 */
+#define HAS_PWM(ix)		(1 << ((ix) + 11))	/* bits 11-16 */
+#define HAS_IN7			(1 << 17)		/* bit 17 */
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct dme1737_data {
+	struct i2c_client *client;	/* for I2C devices only */
+	struct device *hwmon_dev;
+	const char *name;
+	unsigned int addr;		/* for ISA devices only */
+
+	struct mutex update_lock;
+	int valid;			/* !=0 if following fields are valid */
+	unsigned long last_update;	/* in jiffies */
+	unsigned long last_vbat;	/* in jiffies */
+	enum chips type;
+	const int *in_nominal;		/* pointer to IN_NOMINAL array */
+
+	u8 vid;
+	u8 pwm_rr_en;
+	u32 has_features;
+
+	/* Register values */
+	u16 in[8];
+	u8  in_min[8];
+	u8  in_max[8];
+	s16 temp[3];
+	s8  temp_min[3];
+	s8  temp_max[3];
+	s8  temp_offset[3];
+	u8  config;
+	u8  config2;
+	u8  vrm;
+	u16 fan[6];
+	u16 fan_min[6];
+	u8  fan_max[2];
+	u8  fan_opt[6];
+	u8  pwm[6];
+	u8  pwm_min[3];
+	u8  pwm_config[3];
+	u8  pwm_acz[3];
+	u8  pwm_freq[6];
+	u8  pwm_rr[2];
+	s8  zone_low[3];
+	s8  zone_abs[3];
+	u8  zone_hyst[2];
+	u32 alarms;
+};
+
+/* Nominal voltage values */
+static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
+					 3300};
+static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
+					 3300};
+static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
+					 3300};
+static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
+					 3300, 1500};
+#define IN_NOMINAL(type)	((type) == sch311x ? IN_NOMINAL_SCH311x : \
+				 (type) == sch5027 ? IN_NOMINAL_SCH5027 : \
+				 (type) == sch5127 ? IN_NOMINAL_SCH5127 : \
+				 IN_NOMINAL_DME1737)
+
+/*
+ * Voltage input
+ * Voltage inputs have 16 bits resolution, limit values have 8 bits
+ * resolution.
+ */
+static inline int IN_FROM_REG(int reg, int nominal, int res)
+{
+	return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
+}
+
+static inline int IN_TO_REG(long val, int nominal)
+{
+	return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
+}
+
+/*
+ * Temperature input
+ * The register values represent temperatures in 2's complement notation from
+ * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
+ * values have 8 bits resolution.
+ */
+static inline int TEMP_FROM_REG(int reg, int res)
+{
+	return (reg * 1000) >> (res - 8);
+}
+
+static inline int TEMP_TO_REG(long val)
+{
+	return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
+}
+
+/* Temperature range */
+static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
+				 10000, 13333, 16000, 20000, 26666, 32000,
+				 40000, 53333, 80000};
+
+static inline int TEMP_RANGE_FROM_REG(int reg)
+{
+	return TEMP_RANGE[(reg >> 4) & 0x0f];
+}
+
+static int TEMP_RANGE_TO_REG(long val, int reg)
+{
+	int i;
+
+	for (i = 15; i > 0; i--) {
+		if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2)
+			break;
+	}
+
+	return (reg & 0x0f) | (i << 4);
+}
+
+/*
+ * Temperature hysteresis
+ * Register layout:
+ *    reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx]
+ */
+static inline int TEMP_HYST_FROM_REG(int reg, int ix)
+{
+	return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
+}
+
+static inline int TEMP_HYST_TO_REG(long val, int ix, int reg)
+{
+	int hyst = clamp_val((val + 500) / 1000, 0, 15);
+
+	return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
+}
+
+/* Fan input RPM */
+static inline int FAN_FROM_REG(int reg, int tpc)
+{
+	if (tpc)
+		return tpc * reg;
+	else
+		return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg;
+}
+
+static inline int FAN_TO_REG(long val, int tpc)
+{
+	if (tpc) {
+		return clamp_val(val / tpc, 0, 0xffff);
+	} else {
+		return (val <= 0) ? 0xffff :
+			clamp_val(90000 * 60 / val, 0, 0xfffe);
+	}
+}
+
+/*
+ * Fan TPC (tach pulse count)
+ * Converts a register value to a TPC multiplier or returns 0 if the tachometer
+ * is configured in legacy (non-tpc) mode
+ */
+static inline int FAN_TPC_FROM_REG(int reg)
+{
+	return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
+}
+
+/*
+ * Fan type
+ * The type of a fan is expressed in number of pulses-per-revolution that it
+ * emits
+ */
+static inline int FAN_TYPE_FROM_REG(int reg)
+{
+	int edge = (reg >> 1) & 0x03;
+
+	return (edge > 0) ? 1 << (edge - 1) : 0;
+}
+
+static inline int FAN_TYPE_TO_REG(long val, int reg)
+{
+	int edge = (val == 4) ? 3 : val;
+
+	return (reg & 0xf9) | (edge << 1);
+}
+
+/* Fan max RPM */
+static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
+			      0x11, 0x0f, 0x0e};
+
+static int FAN_MAX_FROM_REG(int reg)
+{
+	int i;
+
+	for (i = 10; i > 0; i--) {
+		if (reg == FAN_MAX[i])
+			break;
+	}
+
+	return 1000 + i * 500;
+}
+
+static int FAN_MAX_TO_REG(long val)
+{
+	int i;
+
+	for (i = 10; i > 0; i--) {
+		if (val > (1000 + (i - 1) * 500))
+			break;
+	}
+
+	return FAN_MAX[i];
+}
+
+/*
+ * PWM enable
+ * Register to enable mapping:
+ * 000:  2  fan on zone 1 auto
+ * 001:  2  fan on zone 2 auto
+ * 010:  2  fan on zone 3 auto
+ * 011:  0  fan full on
+ * 100: -1  fan disabled
+ * 101:  2  fan on hottest of zones 2,3 auto
+ * 110:  2  fan on hottest of zones 1,2,3 auto
+ * 111:  1  fan in manual mode
+ */
+static inline int PWM_EN_FROM_REG(int reg)
+{
+	static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
+
+	return en[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_EN_TO_REG(int val, int reg)
+{
+	int en = (val == 1) ? 7 : 3;
+
+	return (reg & 0x1f) | ((en & 0x07) << 5);
+}
+
+/*
+ * PWM auto channels zone
+ * Register to auto channels zone mapping (ACZ is a bitfield with bit x
+ * corresponding to zone x+1):
+ * 000: 001  fan on zone 1 auto
+ * 001: 010  fan on zone 2 auto
+ * 010: 100  fan on zone 3 auto
+ * 011: 000  fan full on
+ * 100: 000  fan disabled
+ * 101: 110  fan on hottest of zones 2,3 auto
+ * 110: 111  fan on hottest of zones 1,2,3 auto
+ * 111: 000  fan in manual mode
+ */
+static inline int PWM_ACZ_FROM_REG(int reg)
+{
+	static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
+
+	return acz[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_ACZ_TO_REG(long val, int reg)
+{
+	int acz = (val == 4) ? 2 : val - 1;
+
+	return (reg & 0x1f) | ((acz & 0x07) << 5);
+}
+
+/* PWM frequency */
+static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
+			       15000, 20000, 30000, 25000, 0, 0, 0, 0};
+
+static inline int PWM_FREQ_FROM_REG(int reg)
+{
+	return PWM_FREQ[reg & 0x0f];
+}
+
+static int PWM_FREQ_TO_REG(long val, int reg)
+{
+	int i;
+
+	/* the first two cases are special - stupid chip design! */
+	if (val > 27500) {
+		i = 10;
+	} else if (val > 22500) {
+		i = 11;
+	} else {
+		for (i = 9; i > 0; i--) {
+			if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2)
+				break;
+		}
+	}
+
+	return (reg & 0xf0) | i;
+}
+
+/*
+ * PWM ramp rate
+ * Register layout:
+ *    reg[0] = [OFF3,  OFF2,  OFF1,  RES,   RR1-E, RR1-2, RR1-1, RR1-0]
+ *    reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0]
+ */
+static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
+
+static inline int PWM_RR_FROM_REG(int reg, int ix)
+{
+	int rr = (ix == 1) ? reg >> 4 : reg;
+
+	return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
+}
+
+static int PWM_RR_TO_REG(long val, int ix, int reg)
+{
+	int i;
+
+	for (i = 0; i < 7; i++) {
+		if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2)
+			break;
+	}
+
+	return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
+}
+
+/* PWM ramp rate enable */
+static inline int PWM_RR_EN_FROM_REG(int reg, int ix)
+{
+	return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
+}
+
+static inline int PWM_RR_EN_TO_REG(long val, int ix, int reg)
+{
+	int en = (ix == 1) ? 0x80 : 0x08;
+
+	return val ? reg | en : reg & ~en;
+}
+
+/*
+ * PWM min/off
+ * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
+ * the register layout).
+ */
+static inline int PWM_OFF_FROM_REG(int reg, int ix)
+{
+	return (reg >> (ix + 5)) & 0x01;
+}
+
+static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
+{
+	return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ *
+ * ISA access is performed through an index/data register pair and needs to
+ * be protected by a mutex during runtime (not required for initialization).
+ * We use data->update_lock for this and need to ensure that we acquire it
+ * before calling dme1737_read or dme1737_write.
+ * --------------------------------------------------------------------- */
+
+static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
+{
+	struct i2c_client *client = data->client;
+	s32 val;
+
+	if (client) { /* I2C device */
+		val = i2c_smbus_read_byte_data(client, reg);
+
+		if (val < 0) {
+			dev_warn(&client->dev,
+				 "Read from register 0x%02x failed! %s\n",
+				 reg, DO_REPORT);
+		}
+	} else { /* ISA device */
+		outb(reg, data->addr);
+		val = inb(data->addr + 1);
+	}
+
+	return val;
+}
+
+static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
+{
+	struct i2c_client *client = data->client;
+	s32 res = 0;
+
+	if (client) { /* I2C device */
+		res = i2c_smbus_write_byte_data(client, reg, val);
+
+		if (res < 0) {
+			dev_warn(&client->dev,
+				 "Write to register 0x%02x failed! %s\n",
+				 reg, DO_REPORT);
+		}
+	} else { /* ISA device */
+		outb(reg, data->addr);
+		outb(val, data->addr + 1);
+	}
+
+	return res;
+}
+
+static struct dme1737_data *dme1737_update_device(struct device *dev)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	int ix;
+	u8 lsb[6];
+
+	mutex_lock(&data->update_lock);
+
+	/* Enable a Vbat monitoring cycle every 10 mins */
+	if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
+		dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
+						DME1737_REG_CONFIG) | 0x10);
+		data->last_vbat = jiffies;
+	}
+
+	/* Sample register contents every 1 sec */
+	if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
+		if (data->has_features & HAS_VID) {
+			data->vid = dme1737_read(data, DME1737_REG_VID) &
+				0x3f;
+		}
+
+		/* In (voltage) registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+			/*
+			 * Voltage inputs are stored as 16 bit values even
+			 * though they have only 12 bits resolution. This is
+			 * to make it consistent with the temp inputs.
+			 */
+			if (ix == 7 && !(data->has_features & HAS_IN7))
+				continue;
+			data->in[ix] = dme1737_read(data,
+					DME1737_REG_IN(ix)) << 8;
+			data->in_min[ix] = dme1737_read(data,
+					DME1737_REG_IN_MIN(ix));
+			data->in_max[ix] = dme1737_read(data,
+					DME1737_REG_IN_MAX(ix));
+		}
+
+		/* Temp registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+			/*
+			 * Temp inputs are stored as 16 bit values even
+			 * though they have only 12 bits resolution. This is
+			 * to take advantage of implicit conversions between
+			 * register values (2's complement) and temp values
+			 * (signed decimal).
+			 */
+			data->temp[ix] = dme1737_read(data,
+					DME1737_REG_TEMP(ix)) << 8;
+			data->temp_min[ix] = dme1737_read(data,
+					DME1737_REG_TEMP_MIN(ix));
+			data->temp_max[ix] = dme1737_read(data,
+					DME1737_REG_TEMP_MAX(ix));
+			if (data->has_features & HAS_TEMP_OFFSET) {
+				data->temp_offset[ix] = dme1737_read(data,
+						DME1737_REG_TEMP_OFFSET(ix));
+			}
+		}
+
+		/*
+		 * In and temp LSB registers
+		 * The LSBs are latched when the MSBs are read, so the order in
+		 * which the registers are read (MSB first, then LSB) is
+		 * important!
+		 */
+		for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+			if (ix == 5 && !(data->has_features & HAS_IN7))
+				continue;
+			lsb[ix] = dme1737_read(data,
+					DME1737_REG_IN_TEMP_LSB(ix));
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+			if (ix == 7 && !(data->has_features & HAS_IN7))
+				continue;
+			data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
+					DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+			data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
+					DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
+		}
+
+		/* Fan registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+			/*
+			 * Skip reading registers if optional fans are not
+			 * present
+			 */
+			if (!(data->has_features & HAS_FAN(ix)))
+				continue;
+			data->fan[ix] = dme1737_read(data,
+					DME1737_REG_FAN(ix));
+			data->fan[ix] |= dme1737_read(data,
+					DME1737_REG_FAN(ix) + 1) << 8;
+			data->fan_min[ix] = dme1737_read(data,
+					DME1737_REG_FAN_MIN(ix));
+			data->fan_min[ix] |= dme1737_read(data,
+					DME1737_REG_FAN_MIN(ix) + 1) << 8;
+			data->fan_opt[ix] = dme1737_read(data,
+					DME1737_REG_FAN_OPT(ix));
+			/* fan_max exists only for fan[5-6] */
+			if (ix > 3) {
+				data->fan_max[ix - 4] = dme1737_read(data,
+					DME1737_REG_FAN_MAX(ix));
+			}
+		}
+
+		/* PWM registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
+			/*
+			 * Skip reading registers if optional PWMs are not
+			 * present
+			 */
+			if (!(data->has_features & HAS_PWM(ix)))
+				continue;
+			data->pwm[ix] = dme1737_read(data,
+					DME1737_REG_PWM(ix));
+			data->pwm_freq[ix] = dme1737_read(data,
+					DME1737_REG_PWM_FREQ(ix));
+			/* pwm_config and pwm_min exist only for pwm[1-3] */
+			if (ix < 3) {
+				data->pwm_config[ix] = dme1737_read(data,
+						DME1737_REG_PWM_CONFIG(ix));
+				data->pwm_min[ix] = dme1737_read(data,
+						DME1737_REG_PWM_MIN(ix));
+			}
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
+			data->pwm_rr[ix] = dme1737_read(data,
+						DME1737_REG_PWM_RR(ix));
+		}
+
+		/* Thermal zone registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
+			/* Skip reading registers if zone3 is not present */
+			if ((ix == 2) && !(data->has_features & HAS_ZONE3))
+				continue;
+			/* sch5127 zone2 registers are special */
+			if ((ix == 1) && (data->type == sch5127)) {
+				data->zone_low[1] = dme1737_read(data,
+						DME1737_REG_ZONE_LOW(2));
+				data->zone_abs[1] = dme1737_read(data,
+						DME1737_REG_ZONE_ABS(2));
+			} else {
+				data->zone_low[ix] = dme1737_read(data,
+						DME1737_REG_ZONE_LOW(ix));
+				data->zone_abs[ix] = dme1737_read(data,
+						DME1737_REG_ZONE_ABS(ix));
+			}
+		}
+		if (data->has_features & HAS_ZONE_HYST) {
+			for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
+				data->zone_hyst[ix] = dme1737_read(data,
+						DME1737_REG_ZONE_HYST(ix));
+			}
+		}
+
+		/* Alarm registers */
+		data->alarms = dme1737_read(data,
+						DME1737_REG_ALARM1);
+		/*
+		 * Bit 7 tells us if the other alarm registers are non-zero and
+		 * therefore also need to be read
+		 */
+		if (data->alarms & 0x80) {
+			data->alarms |= dme1737_read(data,
+						DME1737_REG_ALARM2) << 8;
+			data->alarms |= dme1737_read(data,
+						DME1737_REG_ALARM3) << 16;
+		}
+
+		/*
+		 * The ISA chips require explicit clearing of alarm bits.
+		 * Don't worry, an alarm will come back if the condition
+		 * that causes it still exists
+		 */
+		if (!data->client) {
+			if (data->alarms & 0xff0000)
+				dme1737_write(data, DME1737_REG_ALARM3, 0xff);
+			if (data->alarms & 0xff00)
+				dme1737_write(data, DME1737_REG_ALARM2, 0xff);
+			if (data->alarms & 0xff)
+				dme1737_write(data, DME1737_REG_ALARM1, 0xff);
+		}
+
+		data->last_update = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs attributes
+ * ix = [0-7]
+ * --------------------------------------------------------------------- */
+
+#define SYS_IN_INPUT	0
+#define SYS_IN_MIN	1
+#define SYS_IN_MAX	2
+#define SYS_IN_ALARM	3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_IN_INPUT:
+		res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16);
+		break;
+	case SYS_IN_MIN:
+		res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8);
+		break;
+	case SYS_IN_MAX:
+		res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8);
+		break;
+	case SYS_IN_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_IN_MIN:
+		data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
+		dme1737_write(data, DME1737_REG_IN_MIN(ix),
+			      data->in_min[ix]);
+		break;
+	case SYS_IN_MAX:
+		data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
+		dme1737_write(data, DME1737_REG_IN_MAX(ix),
+			      data->in_max[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_TEMP_INPUT			0
+#define SYS_TEMP_MIN			1
+#define SYS_TEMP_MAX			2
+#define SYS_TEMP_OFFSET			3
+#define SYS_TEMP_ALARM			4
+#define SYS_TEMP_FAULT			5
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_TEMP_INPUT:
+		res = TEMP_FROM_REG(data->temp[ix], 16);
+		break;
+	case SYS_TEMP_MIN:
+		res = TEMP_FROM_REG(data->temp_min[ix], 8);
+		break;
+	case SYS_TEMP_MAX:
+		res = TEMP_FROM_REG(data->temp_max[ix], 8);
+		break;
+	case SYS_TEMP_OFFSET:
+		res = TEMP_FROM_REG(data->temp_offset[ix], 8);
+		break;
+	case SYS_TEMP_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
+		break;
+	case SYS_TEMP_FAULT:
+		res = (((u16)data->temp[ix] & 0xff00) == 0x8000);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_TEMP_MIN:
+		data->temp_min[ix] = TEMP_TO_REG(val);
+		dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
+			      data->temp_min[ix]);
+		break;
+	case SYS_TEMP_MAX:
+		data->temp_max[ix] = TEMP_TO_REG(val);
+		dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
+			      data->temp_max[ix]);
+		break;
+	case SYS_TEMP_OFFSET:
+		data->temp_offset[ix] = TEMP_TO_REG(val);
+		dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
+			      data->temp_offset[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Zone sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_ZONE_AUTO_CHANNELS_TEMP	0
+#define SYS_ZONE_AUTO_POINT1_TEMP_HYST	1
+#define SYS_ZONE_AUTO_POINT1_TEMP	2
+#define SYS_ZONE_AUTO_POINT2_TEMP	3
+#define SYS_ZONE_AUTO_POINT3_TEMP	4
+
+static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_ZONE_AUTO_CHANNELS_TEMP:
+		/* check config2 for non-standard temp-to-zone mapping */
+		if ((ix == 1) && (data->config2 & 0x02))
+			res = 4;
+		else
+			res = 1 << ix;
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+		res = TEMP_FROM_REG(data->zone_low[ix], 8) -
+		      TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP:
+		res = TEMP_FROM_REG(data->zone_low[ix], 8);
+		break;
+	case SYS_ZONE_AUTO_POINT2_TEMP:
+		/* pwm_freq holds the temp range bits in the upper nibble */
+		res = TEMP_FROM_REG(data->zone_low[ix], 8) +
+		      TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT3_TEMP:
+		res = TEMP_FROM_REG(data->zone_abs[ix], 8);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+		/* Refresh the cache */
+		data->zone_low[ix] = dme1737_read(data,
+						  DME1737_REG_ZONE_LOW(ix));
+		/* Modify the temp hyst value */
+		data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
+					TEMP_FROM_REG(data->zone_low[ix], 8) -
+					val, ix, dme1737_read(data,
+					DME1737_REG_ZONE_HYST(ix == 2)));
+		dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
+			      data->zone_hyst[ix == 2]);
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP:
+		data->zone_low[ix] = TEMP_TO_REG(val);
+		dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
+			      data->zone_low[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT2_TEMP:
+		/* Refresh the cache */
+		data->zone_low[ix] = dme1737_read(data,
+						  DME1737_REG_ZONE_LOW(ix));
+		/*
+		 * Modify the temp range value (which is stored in the upper
+		 * nibble of the pwm_freq register)
+		 */
+		data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
+					TEMP_FROM_REG(data->zone_low[ix], 8),
+					dme1737_read(data,
+					DME1737_REG_PWM_FREQ(ix)));
+		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
+			      data->pwm_freq[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT3_TEMP:
+		data->zone_abs[ix] = TEMP_TO_REG(val);
+		dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
+			      data->zone_abs[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_FAN_INPUT	0
+#define SYS_FAN_MIN	1
+#define SYS_FAN_MAX	2
+#define SYS_FAN_ALARM	3
+#define SYS_FAN_TYPE	4
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_FAN_INPUT:
+		res = FAN_FROM_REG(data->fan[ix],
+				   ix < 4 ? 0 :
+				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		break;
+	case SYS_FAN_MIN:
+		res = FAN_FROM_REG(data->fan_min[ix],
+				   ix < 4 ? 0 :
+				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		break;
+	case SYS_FAN_MAX:
+		/* only valid for fan[5-6] */
+		res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
+		break;
+	case SYS_FAN_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
+		break;
+	case SYS_FAN_TYPE:
+		/* only valid for fan[1-4] */
+		res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_FAN_MIN:
+		if (ix < 4) {
+			data->fan_min[ix] = FAN_TO_REG(val, 0);
+		} else {
+			/* Refresh the cache */
+			data->fan_opt[ix] = dme1737_read(data,
+						DME1737_REG_FAN_OPT(ix));
+			/* Modify the fan min value */
+			data->fan_min[ix] = FAN_TO_REG(val,
+					FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		}
+		dme1737_write(data, DME1737_REG_FAN_MIN(ix),
+			      data->fan_min[ix] & 0xff);
+		dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
+			      data->fan_min[ix] >> 8);
+		break;
+	case SYS_FAN_MAX:
+		/* Only valid for fan[5-6] */
+		data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
+		dme1737_write(data, DME1737_REG_FAN_MAX(ix),
+			      data->fan_max[ix - 4]);
+		break;
+	case SYS_FAN_TYPE:
+		/* Only valid for fan[1-4] */
+		if (!(val == 1 || val == 2 || val == 4)) {
+			count = -EINVAL;
+			dev_warn(dev,
+				 "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
+				 val);
+			goto exit;
+		}
+		data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
+					DME1737_REG_FAN_OPT(ix)));
+		dme1737_write(data, DME1737_REG_FAN_OPT(ix),
+			      data->fan_opt[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+exit:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs attributes
+ * ix = [0-4]
+ * --------------------------------------------------------------------- */
+
+#define SYS_PWM				0
+#define SYS_PWM_FREQ			1
+#define SYS_PWM_ENABLE			2
+#define SYS_PWM_RAMP_RATE		3
+#define SYS_PWM_AUTO_CHANNELS_ZONE	4
+#define SYS_PWM_AUTO_PWM_MIN		5
+#define SYS_PWM_AUTO_POINT1_PWM		6
+#define SYS_PWM_AUTO_POINT2_PWM		7
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_PWM:
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0)
+			res = 255;
+		else
+			res = data->pwm[ix];
+		break;
+	case SYS_PWM_FREQ:
+		res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
+		break;
+	case SYS_PWM_ENABLE:
+		if (ix >= 3)
+			res = 1; /* pwm[5-6] hard-wired to manual mode */
+		else
+			res = PWM_EN_FROM_REG(data->pwm_config[ix]);
+		break;
+	case SYS_PWM_RAMP_RATE:
+		/* Only valid for pwm[1-3] */
+		res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
+		break;
+	case SYS_PWM_AUTO_CHANNELS_ZONE:
+		/* Only valid for pwm[1-3] */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2)
+			res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
+		else
+			res = data->pwm_acz[ix];
+		break;
+	case SYS_PWM_AUTO_PWM_MIN:
+		/* Only valid for pwm[1-3] */
+		if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix))
+			res = data->pwm_min[ix];
+		else
+			res = 0;
+		break;
+	case SYS_PWM_AUTO_POINT1_PWM:
+		/* Only valid for pwm[1-3] */
+		res = data->pwm_min[ix];
+		break;
+	case SYS_PWM_AUTO_POINT2_PWM:
+		/* Only valid for pwm[1-3] */
+		res = 255; /* hard-wired */
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static struct attribute *dme1737_pwm_chmod_attr[];
+static void dme1737_chmod_file(struct device*, struct attribute*, umode_t);
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_PWM:
+		data->pwm[ix] = clamp_val(val, 0, 255);
+		dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
+		break;
+	case SYS_PWM_FREQ:
+		data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
+						DME1737_REG_PWM_FREQ(ix)));
+		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
+			      data->pwm_freq[ix]);
+		break;
+	case SYS_PWM_ENABLE:
+		/* Only valid for pwm[1-3] */
+		if (val < 0 || val > 2) {
+			count = -EINVAL;
+			dev_warn(dev,
+				 "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
+				 val);
+			goto exit;
+		}
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(data,
+						DME1737_REG_PWM_CONFIG(ix));
+		if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
+			/* Bail out if no change */
+			goto exit;
+		}
+		/* Do some housekeeping if we are currently in auto mode */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			/* Save the current zone channel assignment */
+			data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
+							data->pwm_config[ix]);
+			/* Save the current ramp rate state and disable it */
+			data->pwm_rr[ix > 0] = dme1737_read(data,
+						DME1737_REG_PWM_RR(ix > 0));
+			data->pwm_rr_en &= ~(1 << ix);
+			if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
+				data->pwm_rr_en |= (1 << ix);
+				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
+							data->pwm_rr[ix > 0]);
+				dme1737_write(data,
+					      DME1737_REG_PWM_RR(ix > 0),
+					      data->pwm_rr[ix > 0]);
+			}
+		}
+		/* Set the new PWM mode */
+		switch (val) {
+		case 0:
+			/* Change permissions of pwm[ix] to read-only */
+			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
+					   S_IRUGO);
+			/* Turn fan fully on */
+			data->pwm_config[ix] = PWM_EN_TO_REG(0,
+							data->pwm_config[ix]);
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			break;
+		case 1:
+			/* Turn on manual mode */
+			data->pwm_config[ix] = PWM_EN_TO_REG(1,
+							data->pwm_config[ix]);
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			/* Change permissions of pwm[ix] to read-writeable */
+			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
+					   S_IRUGO | S_IWUSR);
+			break;
+		case 2:
+			/* Change permissions of pwm[ix] to read-only */
+			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
+					   S_IRUGO);
+			/*
+			 * Turn on auto mode using the saved zone channel
+			 * assignment
+			 */
+			data->pwm_config[ix] = PWM_ACZ_TO_REG(
+							data->pwm_acz[ix],
+							data->pwm_config[ix]);
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			/* Enable PWM ramp rate if previously enabled */
+			if (data->pwm_rr_en & (1 << ix)) {
+				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
+						dme1737_read(data,
+						DME1737_REG_PWM_RR(ix > 0)));
+				dme1737_write(data,
+					      DME1737_REG_PWM_RR(ix > 0),
+					      data->pwm_rr[ix > 0]);
+			}
+			break;
+		}
+		break;
+	case SYS_PWM_RAMP_RATE:
+		/* Only valid for pwm[1-3] */
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(data,
+						DME1737_REG_PWM_CONFIG(ix));
+		data->pwm_rr[ix > 0] = dme1737_read(data,
+						DME1737_REG_PWM_RR(ix > 0));
+		/* Set the ramp rate value */
+		if (val > 0) {
+			data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
+							data->pwm_rr[ix > 0]);
+		}
+		/*
+		 * Enable/disable the feature only if the associated PWM
+		 * output is in automatic mode.
+		 */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
+							data->pwm_rr[ix > 0]);
+		}
+		dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
+			      data->pwm_rr[ix > 0]);
+		break;
+	case SYS_PWM_AUTO_CHANNELS_ZONE:
+		/* Only valid for pwm[1-3] */
+		if (!(val == 1 || val == 2 || val == 4 ||
+		      val == 6 || val == 7)) {
+			count = -EINVAL;
+			dev_warn(dev,
+				 "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
+				 "or 7.\n", val);
+			goto exit;
+		}
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(data,
+						DME1737_REG_PWM_CONFIG(ix));
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			/*
+			 * PWM is already in auto mode so update the temp
+			 * channel assignment
+			 */
+			data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
+						data->pwm_config[ix]);
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+		} else {
+			/*
+			 * PWM is not in auto mode so we save the temp
+			 * channel assignment for later use
+			 */
+			data->pwm_acz[ix] = val;
+		}
+		break;
+	case SYS_PWM_AUTO_PWM_MIN:
+		/* Only valid for pwm[1-3] */
+		/* Refresh the cache */
+		data->pwm_min[ix] = dme1737_read(data,
+						DME1737_REG_PWM_MIN(ix));
+		/*
+		 * There are only 2 values supported for the auto_pwm_min
+		 * value: 0 or auto_point1_pwm. So if the temperature drops
+		 * below the auto_point1_temp_hyst value, the fan either turns
+		 * off or runs at auto_point1_pwm duty-cycle.
+		 */
+		if (val > ((data->pwm_min[ix] + 1) / 2)) {
+			data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
+						dme1737_read(data,
+						DME1737_REG_PWM_RR(0)));
+		} else {
+			data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
+						dme1737_read(data,
+						DME1737_REG_PWM_RR(0)));
+		}
+		dme1737_write(data, DME1737_REG_PWM_RR(0),
+			      data->pwm_rr[0]);
+		break;
+	case SYS_PWM_AUTO_POINT1_PWM:
+		/* Only valid for pwm[1-3] */
+		data->pwm_min[ix] = clamp_val(val, 0, 255);
+		dme1737_write(data, DME1737_REG_PWM_MIN(ix),
+			      data->pwm_min[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown function %d.\n", fn);
+	}
+exit:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs attributes
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+/* ---------------------------------------------------------------------
+ * Sysfs device attribute defines and structs
+ * --------------------------------------------------------------------- */
+
+/* Voltages 0-7 */
+
+#define SENSOR_DEVICE_ATTR_IN(ix) \
+static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
+	show_in, NULL, SYS_IN_INPUT, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+	show_in, set_in, SYS_IN_MIN, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+	show_in, set_in, SYS_IN_MAX, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
+	show_in, NULL, SYS_IN_ALARM, ix)
+
+SENSOR_DEVICE_ATTR_IN(0);
+SENSOR_DEVICE_ATTR_IN(1);
+SENSOR_DEVICE_ATTR_IN(2);
+SENSOR_DEVICE_ATTR_IN(3);
+SENSOR_DEVICE_ATTR_IN(4);
+SENSOR_DEVICE_ATTR_IN(5);
+SENSOR_DEVICE_ATTR_IN(6);
+SENSOR_DEVICE_ATTR_IN(7);
+
+/* Temperatures 1-3 */
+
+#define SENSOR_DEVICE_ATTR_TEMP(ix) \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
+	show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
+	show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+	show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
+	show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+	show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
+	show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+
+SENSOR_DEVICE_ATTR_TEMP(1);
+SENSOR_DEVICE_ATTR_TEMP(2);
+SENSOR_DEVICE_ATTR_TEMP(3);
+
+/* Zones 1-3 */
+
+#define SENSOR_DEVICE_ATTR_ZONE(ix) \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
+	show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
+	show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
+	show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
+	show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
+	show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+
+SENSOR_DEVICE_ATTR_ZONE(1);
+SENSOR_DEVICE_ATTR_ZONE(2);
+SENSOR_DEVICE_ATTR_ZONE(3);
+
+/* Fans 1-4 */
+
+#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+	show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+	show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+	show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
+	show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_1TO4(1);
+SENSOR_DEVICE_ATTR_FAN_1TO4(2);
+SENSOR_DEVICE_ATTR_FAN_1TO4(3);
+SENSOR_DEVICE_ATTR_FAN_1TO4(4);
+
+/* Fans 5-6 */
+
+#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+	show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+	show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+	show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
+	show_fan, set_fan, SYS_FAN_MAX, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_5TO6(5);
+SENSOR_DEVICE_ATTR_FAN_5TO6(6);
+
+/* PWMs 1-3 */
+
+#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
+	show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_1TO3(1);
+SENSOR_DEVICE_ATTR_PWM_1TO3(2);
+SENSOR_DEVICE_ATTR_PWM_1TO3(3);
+
+/* PWMs 5-6 */
+
+#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+	show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+	show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_5TO6(5);
+SENSOR_DEVICE_ATTR_PWM_5TO6(6);
+
+/* Misc */
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);   /* for ISA devices */
+
+/*
+ * This struct holds all the attributes that are always present and need to be
+ * created unconditionally. The attributes that need modification of their
+ * permissions are created read-only and write permissions are added or removed
+ * on the fly when required
+ */
+static struct attribute *dme1737_attr[] = {
+	/* Voltages */
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	/* Temperatures */
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	/* Zones */
+	&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_group = {
+	.attrs = dme1737_attr,
+};
+
+/*
+ * The following struct holds temp offset attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737, SCH311x
+ */
+static struct attribute *dme1737_temp_offset_attr[] = {
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_temp_offset_group = {
+	.attrs = dme1737_temp_offset_attr,
+};
+
+/*
+ * The following struct holds VID related attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737
+ */
+static struct attribute *dme1737_vid_attr[] = {
+	&dev_attr_vrm.attr,
+	&dev_attr_cpu0_vid.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_vid_group = {
+	.attrs = dme1737_vid_attr,
+};
+
+/*
+ * The following struct holds temp zone 3 related attributes, which are not
+ * available in all chips. The following chips support them:
+ * DME1737, SCH311x, SCH5027
+ */
+static struct attribute *dme1737_zone3_attr[] = {
+	&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_zone3_group = {
+	.attrs = dme1737_zone3_attr,
+};
+
+
+/*
+ * The following struct holds temp zone hysteresis related attributes, which
+ * are not available in all chips. The following chips support them:
+ * DME1737, SCH311x
+ */
+static struct attribute *dme1737_zone_hyst_attr[] = {
+	&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_zone_hyst_group = {
+	.attrs = dme1737_zone_hyst_attr,
+};
+
+/*
+ * The following struct holds voltage in7 related attributes, which
+ * are not available in all chips. The following chips support them:
+ * SCH5127
+ */
+static struct attribute *dme1737_in7_attr[] = {
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_in7_group = {
+	.attrs = dme1737_in7_attr,
+};
+
+/*
+ * The following structs hold the PWM attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load.
+ */
+static struct attribute *dme1737_pwm1_attr[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm2_attr[] = {
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm3_attr[] = {
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm5_attr[] = {
+	&sensor_dev_attr_pwm5.dev_attr.attr,
+	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm5_enable.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm6_attr[] = {
+	&sensor_dev_attr_pwm6.dev_attr.attr,
+	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm6_enable.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_pwm_group[] = {
+	{ .attrs = dme1737_pwm1_attr },
+	{ .attrs = dme1737_pwm2_attr },
+	{ .attrs = dme1737_pwm3_attr },
+	{ .attrs = NULL },
+	{ .attrs = dme1737_pwm5_attr },
+	{ .attrs = dme1737_pwm6_attr },
+};
+
+/*
+ * The following struct holds auto PWM min attributes, which are not available
+ * in all chips. Their creation depends on the chip type which is determined
+ * during module load.
+ */
+static struct attribute *dme1737_auto_pwm_min_attr[] = {
+	&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
+};
+
+/*
+ * The following structs hold the fan attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load.
+ */
+static struct attribute *dme1737_fan1_attr[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_type.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_fan2_attr[] = {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_type.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_fan3_attr[] = {
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_type.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_fan4_attr[] = {
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan4_type.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_fan5_attr[] = {
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_min.dev_attr.attr,
+	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan5_max.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_fan6_attr[] = {
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_min.dev_attr.attr,
+	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan6_max.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_fan_group[] = {
+	{ .attrs = dme1737_fan1_attr },
+	{ .attrs = dme1737_fan2_attr },
+	{ .attrs = dme1737_fan3_attr },
+	{ .attrs = dme1737_fan4_attr },
+	{ .attrs = dme1737_fan5_attr },
+	{ .attrs = dme1737_fan6_attr },
+};
+
+/*
+ * The permissions of the following zone attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only.
+ */
+static struct attribute *dme1737_zone_chmod_attr[] = {
+	&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_zone_chmod_group = {
+	.attrs = dme1737_zone_chmod_attr,
+};
+
+
+/*
+ * The permissions of the following zone 3 attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only.
+ */
+static struct attribute *dme1737_zone3_chmod_attr[] = {
+	&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_zone3_chmod_group = {
+	.attrs = dme1737_zone3_chmod_attr,
+};
+
+/*
+ * The permissions of the following PWM attributes are changed to read-
+ * writeable if the chip is *not* locked and the respective PWM is available.
+ * Otherwise they stay read-only.
+ */
+static struct attribute *dme1737_pwm1_chmod_attr[] = {
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm2_chmod_attr[] = {
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm3_chmod_attr[] = {
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm5_chmod_attr[] = {
+	&sensor_dev_attr_pwm5.dev_attr.attr,
+	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
+	NULL
+};
+static struct attribute *dme1737_pwm6_chmod_attr[] = {
+	&sensor_dev_attr_pwm6.dev_attr.attr,
+	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_pwm_chmod_group[] = {
+	{ .attrs = dme1737_pwm1_chmod_attr },
+	{ .attrs = dme1737_pwm2_chmod_attr },
+	{ .attrs = dme1737_pwm3_chmod_attr },
+	{ .attrs = NULL },
+	{ .attrs = dme1737_pwm5_chmod_attr },
+	{ .attrs = dme1737_pwm6_chmod_attr },
+};
+
+/*
+ * Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
+ * chip is not locked. Otherwise they are read-only.
+ */
+static struct attribute *dme1737_pwm_chmod_attr[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/* ---------------------------------------------------------------------
+ * Super-IO functions
+ * --------------------------------------------------------------------- */
+
+static inline void dme1737_sio_enter(int sio_cip)
+{
+	outb(0x55, sio_cip);
+}
+
+static inline void dme1737_sio_exit(int sio_cip)
+{
+	outb(0xaa, sio_cip);
+}
+
+static inline int dme1737_sio_inb(int sio_cip, int reg)
+{
+	outb(reg, sio_cip);
+	return inb(sio_cip + 1);
+}
+
+static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
+{
+	outb(reg, sio_cip);
+	outb(val, sio_cip + 1);
+}
+
+/* ---------------------------------------------------------------------
+ * Device initialization
+ * --------------------------------------------------------------------- */
+
+static int dme1737_i2c_get_features(int, struct dme1737_data*);
+
+static void dme1737_chmod_file(struct device *dev,
+			       struct attribute *attr, umode_t mode)
+{
+	if (sysfs_chmod_file(&dev->kobj, attr, mode)) {
+		dev_warn(dev, "Failed to change permissions of %s.\n",
+			 attr->name);
+	}
+}
+
+static void dme1737_chmod_group(struct device *dev,
+				const struct attribute_group *group,
+				umode_t mode)
+{
+	struct attribute **attr;
+
+	for (attr = group->attrs; *attr; attr++)
+		dme1737_chmod_file(dev, *attr, mode);
+}
+
+static void dme1737_remove_files(struct device *dev)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	int ix;
+
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+		if (data->has_features & HAS_FAN(ix)) {
+			sysfs_remove_group(&dev->kobj,
+					   &dme1737_fan_group[ix]);
+		}
+	}
+
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+		if (data->has_features & HAS_PWM(ix)) {
+			sysfs_remove_group(&dev->kobj,
+					   &dme1737_pwm_group[ix]);
+			if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
+				sysfs_remove_file(&dev->kobj,
+						dme1737_auto_pwm_min_attr[ix]);
+			}
+		}
+	}
+
+	if (data->has_features & HAS_TEMP_OFFSET)
+		sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
+	if (data->has_features & HAS_VID)
+		sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
+	if (data->has_features & HAS_ZONE3)
+		sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
+	if (data->has_features & HAS_ZONE_HYST)
+		sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
+	if (data->has_features & HAS_IN7)
+		sysfs_remove_group(&dev->kobj, &dme1737_in7_group);
+	sysfs_remove_group(&dev->kobj, &dme1737_group);
+
+	if (!data->client)
+		sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
+}
+
+static int dme1737_create_files(struct device *dev)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	int err, ix;
+
+	/* Create a name attribute for ISA devices */
+	if (!data->client) {
+		err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr);
+		if (err)
+			goto exit;
+	}
+
+	/* Create standard sysfs attributes */
+	err = sysfs_create_group(&dev->kobj, &dme1737_group);
+	if (err)
+		goto exit_remove;
+
+	/* Create chip-dependent sysfs attributes */
+	if (data->has_features & HAS_TEMP_OFFSET) {
+		err = sysfs_create_group(&dev->kobj,
+					 &dme1737_temp_offset_group);
+		if (err)
+			goto exit_remove;
+	}
+	if (data->has_features & HAS_VID) {
+		err = sysfs_create_group(&dev->kobj, &dme1737_vid_group);
+		if (err)
+			goto exit_remove;
+	}
+	if (data->has_features & HAS_ZONE3) {
+		err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group);
+		if (err)
+			goto exit_remove;
+	}
+	if (data->has_features & HAS_ZONE_HYST) {
+		err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group);
+		if (err)
+			goto exit_remove;
+	}
+	if (data->has_features & HAS_IN7) {
+		err = sysfs_create_group(&dev->kobj, &dme1737_in7_group);
+		if (err)
+			goto exit_remove;
+	}
+
+	/* Create fan sysfs attributes */
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+		if (data->has_features & HAS_FAN(ix)) {
+			err = sysfs_create_group(&dev->kobj,
+						 &dme1737_fan_group[ix]);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	/* Create PWM sysfs attributes */
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+		if (data->has_features & HAS_PWM(ix)) {
+			err = sysfs_create_group(&dev->kobj,
+						 &dme1737_pwm_group[ix]);
+			if (err)
+				goto exit_remove;
+			if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) {
+				err = sysfs_create_file(&dev->kobj,
+						dme1737_auto_pwm_min_attr[ix]);
+				if (err)
+					goto exit_remove;
+			}
+		}
+	}
+
+	/*
+	 * Inform if the device is locked. Otherwise change the permissions of
+	 * selected attributes from read-only to read-writeable.
+	 */
+	if (data->config & 0x02) {
+		dev_info(dev,
+			 "Device is locked. Some attributes will be read-only.\n");
+	} else {
+		/* Change permissions of zone sysfs attributes */
+		dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
+				    S_IRUGO | S_IWUSR);
+
+		/* Change permissions of chip-dependent sysfs attributes */
+		if (data->has_features & HAS_TEMP_OFFSET) {
+			dme1737_chmod_group(dev, &dme1737_temp_offset_group,
+					    S_IRUGO | S_IWUSR);
+		}
+		if (data->has_features & HAS_ZONE3) {
+			dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
+					    S_IRUGO | S_IWUSR);
+		}
+		if (data->has_features & HAS_ZONE_HYST) {
+			dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
+					    S_IRUGO | S_IWUSR);
+		}
+
+		/* Change permissions of PWM sysfs attributes */
+		for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
+			if (data->has_features & HAS_PWM(ix)) {
+				dme1737_chmod_group(dev,
+						&dme1737_pwm_chmod_group[ix],
+						S_IRUGO | S_IWUSR);
+				if ((data->has_features & HAS_PWM_MIN) &&
+				    ix < 3) {
+					dme1737_chmod_file(dev,
+						dme1737_auto_pwm_min_attr[ix],
+						S_IRUGO | S_IWUSR);
+				}
+			}
+		}
+
+		/* Change permissions of pwm[1-3] if in manual mode */
+		for (ix = 0; ix < 3; ix++) {
+			if ((data->has_features & HAS_PWM(ix)) &&
+			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+				dme1737_chmod_file(dev,
+						dme1737_pwm_chmod_attr[ix],
+						S_IRUGO | S_IWUSR);
+			}
+		}
+	}
+
+	return 0;
+
+exit_remove:
+	dme1737_remove_files(dev);
+exit:
+	return err;
+}
+
+static int dme1737_init_device(struct device *dev)
+{
+	struct dme1737_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ix;
+	u8 reg;
+
+	/* Point to the right nominal voltages array */
+	data->in_nominal = IN_NOMINAL(data->type);
+
+	data->config = dme1737_read(data, DME1737_REG_CONFIG);
+	/* Inform if part is not monitoring/started */
+	if (!(data->config & 0x01)) {
+		if (!force_start) {
+			dev_err(dev,
+				"Device is not monitoring. Use the force_start load parameter to override.\n");
+			return -EFAULT;
+		}
+
+		/* Force monitoring */
+		data->config |= 0x01;
+		dme1737_write(data, DME1737_REG_CONFIG, data->config);
+	}
+	/* Inform if part is not ready */
+	if (!(data->config & 0x04)) {
+		dev_err(dev, "Device is not ready.\n");
+		return -EFAULT;
+	}
+
+	/*
+	 * Determine which optional fan and pwm features are enabled (only
+	 * valid for I2C devices)
+	 */
+	if (client) {   /* I2C chip */
+		data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
+		/* Check if optional fan3 input is enabled */
+		if (data->config2 & 0x04)
+			data->has_features |= HAS_FAN(2);
+
+		/*
+		 * Fan4 and pwm3 are only available if the client's I2C address
+		 * is the default 0x2e. Otherwise the I/Os associated with
+		 * these functions are used for addr enable/select.
+		 */
+		if (client->addr == 0x2e)
+			data->has_features |= HAS_FAN(3) | HAS_PWM(2);
+
+		/*
+		 * Determine which of the optional fan[5-6] and pwm[5-6]
+		 * features are enabled. For this, we need to query the runtime
+		 * registers through the Super-IO LPC interface. Try both
+		 * config ports 0x2e and 0x4e.
+		 */
+		if (dme1737_i2c_get_features(0x2e, data) &&
+		    dme1737_i2c_get_features(0x4e, data)) {
+			dev_warn(dev,
+				 "Failed to query Super-IO for optional features.\n");
+		}
+	}
+
+	/* Fan[1-2] and pwm[1-2] are present in all chips */
+	data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
+
+	/* Chip-dependent features */
+	switch (data->type) {
+	case dme1737:
+		data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
+			HAS_ZONE_HYST | HAS_PWM_MIN;
+		break;
+	case sch311x:
+		data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
+			HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
+		break;
+	case sch5027:
+		data->has_features |= HAS_ZONE3;
+		break;
+	case sch5127:
+		data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7;
+		break;
+	default:
+		break;
+	}
+
+	dev_info(dev,
+		 "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+		 (data->has_features & HAS_PWM(2)) ? "yes" : "no",
+		 (data->has_features & HAS_PWM(4)) ? "yes" : "no",
+		 (data->has_features & HAS_PWM(5)) ? "yes" : "no",
+		 (data->has_features & HAS_FAN(2)) ? "yes" : "no",
+		 (data->has_features & HAS_FAN(3)) ? "yes" : "no",
+		 (data->has_features & HAS_FAN(4)) ? "yes" : "no",
+		 (data->has_features & HAS_FAN(5)) ? "yes" : "no");
+
+	reg = dme1737_read(data, DME1737_REG_TACH_PWM);
+	/* Inform if fan-to-pwm mapping differs from the default */
+	if (client && reg != 0xa4) {   /* I2C chip */
+		dev_warn(dev,
+			 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
+			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+			 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
+			 DO_REPORT);
+	} else if (!client && reg != 0x24) {   /* ISA chip */
+		dev_warn(dev,
+			 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
+			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+			 ((reg >> 4) & 0x03) + 1, DO_REPORT);
+	}
+
+	/*
+	 * Switch pwm[1-3] to manual mode if they are currently disabled and
+	 * set the duty-cycles to 0% (which is identical to the PWMs being
+	 * disabled).
+	 */
+	if (!(data->config & 0x02)) {
+		for (ix = 0; ix < 3; ix++) {
+			data->pwm_config[ix] = dme1737_read(data,
+						DME1737_REG_PWM_CONFIG(ix));
+			if ((data->has_features & HAS_PWM(ix)) &&
+			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
+				dev_info(dev,
+					 "Switching pwm%d to manual mode.\n",
+					 ix + 1);
+				data->pwm_config[ix] = PWM_EN_TO_REG(1,
+							data->pwm_config[ix]);
+				dme1737_write(data, DME1737_REG_PWM(ix), 0);
+				dme1737_write(data,
+					      DME1737_REG_PWM_CONFIG(ix),
+					      data->pwm_config[ix]);
+			}
+		}
+	}
+
+	/* Initialize the default PWM auto channels zone (acz) assignments */
+	data->pwm_acz[0] = 1;	/* pwm1 -> zone1 */
+	data->pwm_acz[1] = 2;	/* pwm2 -> zone2 */
+	data->pwm_acz[2] = 4;	/* pwm3 -> zone3 */
+
+	/* Set VRM */
+	if (data->has_features & HAS_VID)
+		data->vrm = vid_which_vrm();
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * I2C device detection and registration
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_i2c_driver;
+
+static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
+{
+	int err = 0, reg;
+	u16 addr;
+
+	dme1737_sio_enter(sio_cip);
+
+	/*
+	 * Check device ID
+	 * We currently know about two kinds of DME1737 and SCH5027.
+	 */
+	reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
+	if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
+	      reg == SCH5027_ID)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* Select logical device A (runtime registers) */
+	dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+	/* Get the base address of the runtime registers */
+	addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+		dme1737_sio_inb(sio_cip, 0x61);
+	if (!addr) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/*
+	 * Read the runtime registers to determine which optional features
+	 * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+	 * to '10' if the respective feature is enabled.
+	 */
+	if ((inb(addr + 0x43) & 0x0c) == 0x08) /* fan6 */
+		data->has_features |= HAS_FAN(5);
+	if ((inb(addr + 0x44) & 0x0c) == 0x08) /* pwm6 */
+		data->has_features |= HAS_PWM(5);
+	if ((inb(addr + 0x45) & 0x0c) == 0x08) /* fan5 */
+		data->has_features |= HAS_FAN(4);
+	if ((inb(addr + 0x46) & 0x0c) == 0x08) /* pwm5 */
+		data->has_features |= HAS_PWM(4);
+
+exit:
+	dme1737_sio_exit(sio_cip);
+
+	return err;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int dme1737_i2c_detect(struct i2c_client *client,
+			      struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &adapter->dev;
+	u8 company, verstep = 0;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
+	verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
+
+	if (company == DME1737_COMPANY_SMSC &&
+	    verstep == SCH5027_VERSTEP) {
+		name = "sch5027";
+	} else if (company == DME1737_COMPANY_SMSC &&
+		   (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
+		name = "dme1737";
+	} else {
+		return -ENODEV;
+	}
+
+	dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
+		 verstep == SCH5027_VERSTEP ? "SCH5027" : "DME1737",
+		 client->addr, verstep);
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int dme1737_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct dme1737_data *data;
+	struct device *dev = &client->dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->type = id->driver_data;
+	data->client = client;
+	data->name = client->name;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the DME1737 chip */
+	err = dme1737_init_device(dev);
+	if (err) {
+		dev_err(dev, "Failed to initialize device.\n");
+		return err;
+	}
+
+	/* Create sysfs files */
+	err = dme1737_create_files(dev);
+	if (err) {
+		dev_err(dev, "Failed to create sysfs files.\n");
+		return err;
+	}
+
+	/* Register device */
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(dev, "Failed to register device.\n");
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	dme1737_remove_files(dev);
+	return err;
+}
+
+static int dme1737_i2c_remove(struct i2c_client *client)
+{
+	struct dme1737_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	dme1737_remove_files(&client->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id dme1737_id[] = {
+	{ "dme1737", dme1737 },
+	{ "sch5027", sch5027 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, dme1737_id);
+
+static struct i2c_driver dme1737_i2c_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "dme1737",
+	},
+	.probe = dme1737_i2c_probe,
+	.remove = dme1737_i2c_remove,
+	.id_table = dme1737_id,
+	.detect = dme1737_i2c_detect,
+	.address_list = normal_i2c,
+};
+
+/* ---------------------------------------------------------------------
+ * ISA device detection and registration
+ * --------------------------------------------------------------------- */
+
+static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
+{
+	int err = 0, reg;
+	unsigned short base_addr;
+
+	dme1737_sio_enter(sio_cip);
+
+	/*
+	 * Check device ID
+	 * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127
+	 */
+	reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
+	if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
+	      reg == SCH5127_ID)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* Select logical device A (runtime registers) */
+	dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+	/* Get the base address of the runtime registers */
+	base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+		     dme1737_sio_inb(sio_cip, 0x61);
+	if (!base_addr) {
+		pr_err("Base address not set\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/*
+	 * Access to the hwmon registers is through an index/data register
+	 * pair located at offset 0x70/0x71.
+	 */
+	*addr = base_addr + 0x70;
+
+exit:
+	dme1737_sio_exit(sio_cip);
+	return err;
+}
+
+static int __init dme1737_isa_device_add(unsigned short addr)
+{
+	struct resource res = {
+		.start	= addr,
+		.end	= addr + DME1737_EXTENT - 1,
+		.name	= "dme1737",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc("dme1737", addr);
+	if (!pdev) {
+		pr_err("Failed to allocate device\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Failed to add device resource (err = %d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Failed to add device (err = %d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+	pdev = NULL;
+exit:
+	return err;
+}
+
+static int dme1737_isa_probe(struct platform_device *pdev)
+{
+	u8 company, device;
+	struct resource *res;
+	struct dme1737_data *data;
+	struct device *dev = &pdev->dev;
+	int err;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
+		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
+			(unsigned short)res->start,
+			(unsigned short)res->start + DME1737_EXTENT - 1);
+		return -EBUSY;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = res->start;
+	platform_set_drvdata(pdev, data);
+
+	/* Skip chip detection if module is loaded with force_id parameter */
+	switch (force_id) {
+	case SCH3112_ID:
+	case SCH3114_ID:
+	case SCH3116_ID:
+		data->type = sch311x;
+		break;
+	case SCH5127_ID:
+		data->type = sch5127;
+		break;
+	default:
+		company = dme1737_read(data, DME1737_REG_COMPANY);
+		device = dme1737_read(data, DME1737_REG_DEVICE);
+
+		if ((company == DME1737_COMPANY_SMSC) &&
+		    (device == SCH311X_DEVICE)) {
+			data->type = sch311x;
+		} else if ((company == DME1737_COMPANY_SMSC) &&
+			   (device == SCH5127_DEVICE)) {
+			data->type = sch5127;
+		} else {
+			return -ENODEV;
+		}
+	}
+
+	if (data->type == sch5127)
+		data->name = "sch5127";
+	else
+		data->name = "sch311x";
+
+	/* Initialize the mutex */
+	mutex_init(&data->update_lock);
+
+	dev_info(dev, "Found a %s chip at 0x%04x\n",
+		 data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
+
+	/* Initialize the chip */
+	err = dme1737_init_device(dev);
+	if (err) {
+		dev_err(dev, "Failed to initialize device.\n");
+		return err;
+	}
+
+	/* Create sysfs files */
+	err = dme1737_create_files(dev);
+	if (err) {
+		dev_err(dev, "Failed to create sysfs files.\n");
+		return err;
+	}
+
+	/* Register device */
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(dev, "Failed to register device.\n");
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+
+	return 0;
+
+exit_remove_files:
+	dme1737_remove_files(dev);
+	return err;
+}
+
+static int dme1737_isa_remove(struct platform_device *pdev)
+{
+	struct dme1737_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	dme1737_remove_files(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver dme1737_isa_driver = {
+	.driver = {
+		.name = "dme1737",
+	},
+	.probe = dme1737_isa_probe,
+	.remove = dme1737_isa_remove,
+};
+
+/* ---------------------------------------------------------------------
+ * Module initialization and cleanup
+ * --------------------------------------------------------------------- */
+
+static int __init dme1737_init(void)
+{
+	int err;
+	unsigned short addr;
+
+	err = i2c_add_driver(&dme1737_i2c_driver);
+	if (err)
+		goto exit;
+
+	if (dme1737_isa_detect(0x2e, &addr) &&
+	    dme1737_isa_detect(0x4e, &addr) &&
+	    (!probe_all_addr ||
+	     (dme1737_isa_detect(0x162e, &addr) &&
+	      dme1737_isa_detect(0x164e, &addr)))) {
+		/* Return 0 if we didn't find an ISA device */
+		return 0;
+	}
+
+	err = platform_driver_register(&dme1737_isa_driver);
+	if (err)
+		goto exit_del_i2c_driver;
+
+	/* Sets global pdev as a side effect */
+	err = dme1737_isa_device_add(addr);
+	if (err)
+		goto exit_del_isa_driver;
+
+	return 0;
+
+exit_del_isa_driver:
+	platform_driver_unregister(&dme1737_isa_driver);
+exit_del_i2c_driver:
+	i2c_del_driver(&dme1737_i2c_driver);
+exit:
+	return err;
+}
+
+static void __exit dme1737_exit(void)
+{
+	if (pdev) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&dme1737_isa_driver);
+	}
+
+	i2c_del_driver(&dme1737_i2c_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("DME1737 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(dme1737_init);
+module_exit(dme1737_exit);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
new file mode 100644
index 0000000..8890870
--- /dev/null
+++ b/drivers/hwmon/ds1621.c
@@ -0,0 +1,409 @@
+/*
+ * ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	      monitoring
+ * Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
+ * the help of Jean Delvare <jdelvare@suse.de>
+ *
+ * The DS1621 device is a digital temperature/thermometer with 9-bit
+ * resolution, a thermal alarm output (Tout), and user-defined minimum
+ * and maximum temperature thresholds (TH and TL).
+ *
+ * The DS1625, DS1631, DS1721, and DS1731 are pin compatible with the DS1621
+ * and similar in operation, with slight variations as noted in the device
+ * datasheets (please refer to www.maximintegrated.com for specific
+ * device information).
+ *
+ * Since the DS1621 was the first chipset supported by this driver,
+ * most comments will refer to this chipset, but are actually general
+ * and concern all supported chipsets, unless mentioned otherwise.
+ *
+ * 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>
+#include <linux/kernel.h>
+
+/* Supported devices */
+enum chips { ds1621, ds1625, ds1631, ds1721, ds1731 };
+
+/* Insmod parameters */
+static int polarity = -1;
+module_param(polarity, int, 0);
+MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
+
+/*
+ * The Configuration/Status register
+ *
+ * - DS1621:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | X  | X  |POL |1SHOT|
+ *
+ * - DS1625:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | 1  | 0  |POL |1SHOT|
+ *
+ * - DS1631, DS1731:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | R1 | R0 |POL |1SHOT|
+ *
+ * - DS1721:
+ *   7    6    5    4    3    2    1    0
+ * |Done| X  | X  | U  | R1 | R0 |POL |1SHOT|
+ *
+ * Where:
+ * - 'X' is Reserved
+ * - 'U' is Undefined
+ */
+#define DS1621_REG_CONFIG_NVB		0x10
+#define DS1621_REG_CONFIG_RESOL		0x0C
+#define DS1621_REG_CONFIG_POLARITY	0x02
+#define DS1621_REG_CONFIG_1SHOT		0x01
+#define DS1621_REG_CONFIG_DONE		0x80
+
+#define DS1621_REG_CONFIG_RESOL_SHIFT	2
+
+/* ds1721 conversion rates: {C/LSB, time(ms), resolution bit setting} */
+static const unsigned short ds1721_convrates[] = {
+	94,	/*  9-bits (0.5,  93.75, RES[0..1] = 0 */
+	188,	/* 10-bits (0.25, 187.5, RES[0..1] = 1 */
+	375,	/* 11-bits (0.125,  375, RES[0..1] = 2 */
+	750,	/* 12-bits (0.0625, 750, RES[0..1] = 3 */
+};
+
+#define DS1621_CONVERSION_MAX	750
+#define DS1625_CONVERSION_MAX	500
+
+#define DS1621_TEMP_MAX	125000
+#define DS1621_TEMP_MIN	(-55000)
+
+/* The DS1621 temperature registers */
+static const u8 DS1621_REG_TEMP[3] = {
+	0xAA,		/* input, word, RO */
+	0xA2,		/* min, word, RW */
+	0xA1,		/* max, word, RW */
+};
+#define DS1621_REG_CONF			0xAC /* byte, RW */
+#define DS1621_COM_START		0xEE /* no data */
+#define DS1721_COM_START		0x51 /* no data */
+#define DS1621_COM_STOP			0x22 /* no data */
+
+/* The DS1621 configuration register */
+#define DS1621_ALARM_TEMP_HIGH		0x40
+#define DS1621_ALARM_TEMP_LOW		0x20
+
+/* Conversions */
+#define ALARMS_FROM_REG(val) ((val) & \
+			(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
+
+/* Each client has this additional data */
+struct ds1621_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	enum chips kind;		/* device type */
+
+	u16 temp[3];			/* Register values, word */
+	u8 conf;			/* Register encoding, combined */
+	u8 zbits;			/* Resolution encoded as number of
+					 * zero bits */
+	u16 update_interval;		/* Conversion rate in milliseconds */
+};
+
+static inline int DS1621_TEMP_FROM_REG(u16 reg)
+{
+	return DIV_ROUND_CLOSEST(((s16)reg / 16) * 625, 10);
+}
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG:
+ *  - 1621, 1625: 0.5C/bit, 7 zero-bits
+ *  - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits
+ */
+static inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits)
+{
+	temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX);
+	temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
+	return temp;
+}
+
+static void ds1621_init_client(struct ds1621_data *data,
+			       struct i2c_client *client)
+{
+	u8 conf, new_conf, sreg, resol;
+
+	new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+	/* switch to continuous conversion mode */
+	new_conf &= ~DS1621_REG_CONFIG_1SHOT;
+
+	/* setup output polarity */
+	if (polarity == 0)
+		new_conf &= ~DS1621_REG_CONFIG_POLARITY;
+	else if (polarity == 1)
+		new_conf |= DS1621_REG_CONFIG_POLARITY;
+
+	if (conf != new_conf)
+		i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
+
+	switch (data->kind) {
+	case ds1625:
+		data->update_interval = DS1625_CONVERSION_MAX;
+		data->zbits = 7;
+		sreg = DS1621_COM_START;
+		break;
+	case ds1631:
+	case ds1721:
+	case ds1731:
+		resol = (new_conf & DS1621_REG_CONFIG_RESOL) >>
+			 DS1621_REG_CONFIG_RESOL_SHIFT;
+		data->update_interval = ds1721_convrates[resol];
+		data->zbits = 7 - resol;
+		sreg = DS1721_COM_START;
+		break;
+	default:
+		data->update_interval = DS1621_CONVERSION_MAX;
+		data->zbits = 7;
+		sreg = DS1621_COM_START;
+		break;
+	}
+
+	/* start conversion */
+	i2c_smbus_write_byte(client, sreg);
+}
+
+static struct ds1621_data *ds1621_update_client(struct device *dev)
+{
+	struct ds1621_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 new_conf;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + data->update_interval) ||
+	    !data->valid) {
+		int i;
+
+		dev_dbg(&client->dev, "Starting ds1621 update\n");
+
+		data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+			data->temp[i] = i2c_smbus_read_word_swapped(client,
+							 DS1621_REG_TEMP[i]);
+
+		/* reset alarms if necessary */
+		new_conf = data->conf;
+		if (data->temp[0] > data->temp[1])	/* input > min */
+			new_conf &= ~DS1621_ALARM_TEMP_LOW;
+		if (data->temp[0] < data->temp[2])	/* input < max */
+			new_conf &= ~DS1621_ALARM_TEMP_HIGH;
+		if (data->conf != new_conf)
+			i2c_smbus_write_byte_data(client, DS1621_REG_CONF,
+						  new_conf);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n",
+		       DS1621_TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds1621_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits);
+	i2c_smbus_write_word_swapped(data->client, DS1621_REG_TEMP[attr->index],
+				     data->temp[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n", !!(data->conf & attr->index));
+}
+
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct ds1621_data *data = dev_get_drvdata(dev);
+	return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval);
+}
+
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	struct ds1621_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long convrate;
+	s32 err;
+	int resol = 0;
+
+	err = kstrtoul(buf, 10, &convrate);
+	if (err)
+		return err;
+
+	/* Convert rate into resolution bits */
+	while (resol < (ARRAY_SIZE(ds1721_convrates) - 1) &&
+	       convrate > ds1721_convrates[resol])
+		resol++;
+
+	mutex_lock(&data->update_lock);
+	data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+	data->conf &= ~DS1621_REG_CONFIG_RESOL;
+	data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT);
+	i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf);
+	data->update_interval = ds1721_convrates[resol];
+	data->zbits = 7 - resol;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_convrate,
+		   set_convrate);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+		DS1621_ALARM_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+		DS1621_ALARM_TEMP_HIGH);
+
+static struct attribute *ds1621_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+
+static umode_t ds1621_attribute_visible(struct kobject *kobj,
+					struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct ds1621_data *data = dev_get_drvdata(dev);
+
+	if (attr == &dev_attr_update_interval.attr)
+		if (data->kind == ds1621 || data->kind == ds1625)
+			/* shhh, we're hiding update_interval */
+			return 0;
+	return attr->mode;
+}
+
+static const struct attribute_group ds1621_group = {
+	.attrs = ds1621_attributes,
+	.is_visible = ds1621_attribute_visible
+};
+__ATTRIBUTE_GROUPS(ds1621);
+
+static int ds1621_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct ds1621_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->update_lock);
+
+	data->kind = id->driver_data;
+	data->client = client;
+
+	/* Initialize the DS1621 chip */
+	ds1621_init_client(data, client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   ds1621_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ds1621_id[] = {
+	{ "ds1621", ds1621 },
+	{ "ds1625", ds1625 },
+	{ "ds1631", ds1631 },
+	{ "ds1721", ds1721 },
+	{ "ds1731", ds1731 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ds1621_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds1621_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "ds1621",
+	},
+	.probe		= ds1621_probe,
+	.id_table	= ds1621_id,
+};
+
+module_i2c_driver(ds1621_driver);
+
+MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
+MODULE_DESCRIPTION("DS1621 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
new file mode 100644
index 0000000..0043a4c
--- /dev/null
+++ b/drivers/hwmon/ds620.c
@@ -0,0 +1,272 @@
+/*
+ *  ds620.c - Support for temperature sensor and thermostat DS620
+ *
+ *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ *  based on ds1621.c by Christian W. Zuckschwerdt  <zany@triq.net>
+ *
+ *  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>
+#include <linux/i2c/ds620.h>
+
+/*
+ * Many DS620 constants specified below
+ *  15   14   13   12   11   10   09    08
+ * |Done|NVB |THF |TLF |R1  |R0  |AUTOC|1SHOT|
+ *
+ *  07   06   05   04   03   02   01    00
+ * |PO2 |PO1 |A2  |A1  |A0  |    |     |     |
+ */
+#define DS620_REG_CONFIG_DONE		0x8000
+#define DS620_REG_CONFIG_NVB		0x4000
+#define DS620_REG_CONFIG_THF		0x2000
+#define DS620_REG_CONFIG_TLF		0x1000
+#define DS620_REG_CONFIG_R1		0x0800
+#define DS620_REG_CONFIG_R0		0x0400
+#define DS620_REG_CONFIG_AUTOC		0x0200
+#define DS620_REG_CONFIG_1SHOT		0x0100
+#define DS620_REG_CONFIG_PO2		0x0080
+#define DS620_REG_CONFIG_PO1		0x0040
+#define DS620_REG_CONFIG_A2		0x0020
+#define DS620_REG_CONFIG_A1		0x0010
+#define DS620_REG_CONFIG_A0		0x0008
+
+/* The DS620 registers */
+static const u8 DS620_REG_TEMP[3] = {
+	0xAA,			/* input, word, RO */
+	0xA2,			/* min, word, RW */
+	0xA0,			/* max, word, RW */
+};
+
+#define DS620_REG_CONF		0xAC	/* word, RW */
+#define DS620_COM_START		0x51	/* no data */
+#define DS620_COM_STOP		0x22	/* no data */
+
+/* Each client has this additional data */
+struct ds620_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	s16 temp[3];		/* Register values, word */
+};
+
+static void ds620_init_client(struct i2c_client *client)
+{
+	struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
+	u16 conf, new_conf;
+
+	new_conf = conf =
+	    i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
+
+	/* switch to continuous conversion mode */
+	new_conf &= ~DS620_REG_CONFIG_1SHOT;
+	/* already high at power-on, but don't trust the BIOS! */
+	new_conf |= DS620_REG_CONFIG_PO2;
+	/* thermostat mode according to platform data */
+	if (ds620_info && ds620_info->pomode == 1)
+		new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
+	else if (ds620_info && ds620_info->pomode == 2)
+		new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
+	else
+		new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
+	/* with highest precision */
+	new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
+
+	if (conf != new_conf)
+		i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf);
+
+	/* start conversion */
+	i2c_smbus_write_byte(client, DS620_COM_START);
+}
+
+static struct ds620_data *ds620_update_client(struct device *dev)
+{
+	struct ds620_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct ds620_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int i;
+		int res;
+
+		dev_dbg(&client->dev, "Starting ds620 update\n");
+
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			res = i2c_smbus_read_word_swapped(client,
+							  DS620_REG_TEMP[i]);
+			if (res < 0) {
+				ret = ERR_PTR(res);
+				goto abort;
+			}
+
+			data->temp[i] = res;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds620_data *data = ds620_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	int res;
+	long val;
+
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds620_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	res = kstrtol(buf, 10, &val);
+
+	if (res)
+		return res;
+
+	val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
+
+	mutex_lock(&data->update_lock);
+	data->temp[attr->index] = val;
+	i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index],
+				     data->temp[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds620_data *data = ds620_update_client(dev);
+	struct i2c_client *client;
+	u16 conf, new_conf;
+	int res;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	client = data->client;
+
+	/* reset alarms if necessary */
+	res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
+	if (res < 0)
+		return res;
+
+	new_conf = conf = res;
+	new_conf &= ~attr->index;
+	if (conf != new_conf) {
+		res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF,
+						   new_conf);
+		if (res < 0)
+			return res;
+	}
+
+	return sprintf(buf, "%d\n", !!(conf & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+			  DS620_REG_CONFIG_TLF);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+			  DS620_REG_CONFIG_THF);
+
+static struct attribute *ds620_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(ds620);
+
+static int ds620_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct ds620_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct ds620_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the DS620 chip */
+	ds620_init_client(client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, ds620_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ds620_id[] = {
+	{"ds620", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, ds620_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds620_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		   .name = "ds620",
+	},
+	.probe = ds620_probe,
+	.id_table = ds620_id,
+};
+
+module_i2c_driver(ds620_driver);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("DS620 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
new file mode 100644
index 0000000..1ea7ca5
--- /dev/null
+++ b/drivers/hwmon/emc1403.c
@@ -0,0 +1,499 @@
+/*
+ * emc1403.c - SMSC Thermal Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#define THERMAL_PID_REG		0xfd
+#define THERMAL_SMSC_ID_REG	0xfe
+#define THERMAL_REVISION_REG	0xff
+
+enum emc1403_chip { emc1402, emc1403, emc1404 };
+
+struct thermal_data {
+	struct regmap *regmap;
+	struct mutex mutex;
+	const struct attribute_group *groups[4];
+};
+
+static ssize_t show_temp(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	unsigned int val;
+	int retval;
+
+	retval = regmap_read(data->regmap, sda->index, &val);
+	if (retval < 0)
+		return retval;
+	return sprintf(buf, "%d000\n", val);
+}
+
+static ssize_t show_bit(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	unsigned int val;
+	int retval;
+
+	retval = regmap_read(data->regmap, sda->nr, &val);
+	if (retval < 0)
+		return retval;
+	return sprintf(buf, "%d\n", !!(val & sda->index));
+}
+
+static ssize_t store_temp(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int retval;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+	retval = regmap_write(data->regmap, sda->index,
+			      DIV_ROUND_CLOSEST(val, 1000));
+	if (retval < 0)
+		return retval;
+	return count;
+}
+
+static ssize_t store_bit(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int retval;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	retval = regmap_update_bits(data->regmap, sda->nr, sda->index,
+				    val ? sda->index : 0);
+	if (retval < 0)
+		return retval;
+	return count;
+}
+
+static ssize_t show_hyst_common(struct device *dev,
+				struct device_attribute *attr, char *buf,
+				bool is_min)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	struct regmap *regmap = data->regmap;
+	unsigned int limit;
+	unsigned int hyst;
+	int retval;
+
+	retval = regmap_read(regmap, sda->index, &limit);
+	if (retval < 0)
+		return retval;
+
+	retval = regmap_read(regmap, 0x21, &hyst);
+	if (retval < 0)
+		return retval;
+
+	return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst);
+}
+
+static ssize_t show_hyst(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return show_hyst_common(dev, attr, buf, false);
+}
+
+static ssize_t show_min_hyst(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return show_hyst_common(dev, attr, buf, true);
+}
+
+static ssize_t store_hyst(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct thermal_data *data = dev_get_drvdata(dev);
+	struct regmap *regmap = data->regmap;
+	unsigned int limit;
+	int retval;
+	int hyst;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	retval = regmap_read(regmap, sda->index, &limit);
+	if (retval < 0)
+		goto fail;
+
+	hyst = limit * 1000 - val;
+	hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
+	retval = regmap_write(regmap, 0x21, hyst);
+	if (retval == 0)
+		retval = count;
+fail:
+	mutex_unlock(&data->mutex);
+	return retval;
+}
+
+/*
+ *	Sensors. We pass the actual i2c register to the methods.
+ */
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x06);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x05);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x20);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0x00);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO,
+	show_bit, NULL, 0x36, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO,
+	show_bit, NULL, 0x35, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO,
+	show_bit, NULL, 0x37, 0x01);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x06);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
+	show_hyst, store_hyst, 0x20);
+
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x08);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x07);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x19);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO,
+	show_bit, NULL, 0x36, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO,
+	show_bit, NULL, 0x35, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO,
+	show_bit, NULL, 0x37, 0x02);
+static SENSOR_DEVICE_ATTR(temp2_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x08);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19);
+
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x16);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x15);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x1A);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO,
+	show_bit, NULL, 0x36, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO,
+	show_bit, NULL, 0x35, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO,
+	show_bit, NULL, 0x37, 0x04);
+static SENSOR_DEVICE_ATTR(temp3_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x16);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A);
+
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x2D);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x2C);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR,
+	show_temp, store_temp, 0x30);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A);
+static SENSOR_DEVICE_ATTR_2(temp4_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x08);
+static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO,
+	show_bit, NULL, 0x36, 0x08);
+static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO,
+	show_bit, NULL, 0x35, 0x08);
+static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO,
+	show_bit, NULL, 0x37, 0x08);
+static SENSOR_DEVICE_ATTR(temp4_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x2D);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C);
+static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30);
+
+static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR,
+	show_bit, store_bit, 0x03, 0x40);
+
+static struct attribute *emc1402_attrs[] = {
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_power_state.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group emc1402_group = {
+		.attrs = emc1402_attrs,
+};
+
+static struct attribute *emc1403_attrs[] = {
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group emc1403_group = {
+	.attrs = emc1403_attrs,
+};
+
+static struct attribute *emc1404_attrs[] = {
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group emc1404_group = {
+	.attrs = emc1404_attrs,
+};
+
+/*
+ * EMC14x2 uses a different register and different bits to report alarm and
+ * fault status. For simplicity, provide a separate attribute group for this
+ * chip series.
+ * Since we can not re-use the same attribute names, create a separate attribute
+ * array.
+ */
+static struct sensor_device_attribute_2 emc1402_alarms[] = {
+	SENSOR_ATTR_2(temp1_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x20),
+	SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x40),
+	SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x01),
+
+	SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x02, 0x04),
+	SENSOR_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x08),
+	SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x10),
+	SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x02),
+};
+
+static struct attribute *emc1402_alarm_attrs[] = {
+	&emc1402_alarms[0].dev_attr.attr,
+	&emc1402_alarms[1].dev_attr.attr,
+	&emc1402_alarms[2].dev_attr.attr,
+	&emc1402_alarms[3].dev_attr.attr,
+	&emc1402_alarms[4].dev_attr.attr,
+	&emc1402_alarms[5].dev_attr.attr,
+	&emc1402_alarms[6].dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group emc1402_alarm_group = {
+	.attrs = emc1402_alarm_attrs,
+};
+
+static int emc1403_detect(struct i2c_client *client,
+			struct i2c_board_info *info)
+{
+	int id;
+	/* Check if thermal chip is SMSC and EMC1403 or EMC1423 */
+
+	id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
+	if (id != 0x5d)
+		return -ENODEV;
+
+	id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
+	switch (id) {
+	case 0x20:
+		strlcpy(info->type, "emc1402", I2C_NAME_SIZE);
+		break;
+	case 0x21:
+		strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
+		break;
+	case 0x22:
+		strlcpy(info->type, "emc1422", I2C_NAME_SIZE);
+		break;
+	case 0x23:
+		strlcpy(info->type, "emc1423", I2C_NAME_SIZE);
+		break;
+	case 0x25:
+		strlcpy(info->type, "emc1404", I2C_NAME_SIZE);
+		break;
+	case 0x27:
+		strlcpy(info->type, "emc1424", I2C_NAME_SIZE);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
+	if (id < 0x01 || id > 0x04)
+		return -ENODEV;
+
+	return 0;
+}
+
+static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x00:	/* internal diode high byte */
+	case 0x01:	/* external diode 1 high byte */
+	case 0x02:	/* status */
+	case 0x10:	/* external diode 1 low byte */
+	case 0x1b:	/* external diode fault */
+	case 0x23:	/* external diode 2 high byte */
+	case 0x24:	/* external diode 2 low byte */
+	case 0x29:	/* internal diode low byte */
+	case 0x2a:	/* externl diode 3 high byte */
+	case 0x2b:	/* external diode 3 low byte */
+	case 0x35:	/* high limit status */
+	case 0x36:	/* low limit status */
+	case 0x37:	/* therm limit status */
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config emc1403_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = emc1403_regmap_is_volatile,
+};
+
+static int emc1403_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct thermal_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
+			    GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	mutex_init(&data->mutex);
+
+	switch (id->driver_data) {
+	case emc1404:
+		data->groups[2] = &emc1404_group;
+	case emc1403:
+		data->groups[1] = &emc1403_group;
+	case emc1402:
+		data->groups[0] = &emc1402_group;
+	}
+
+	if (id->driver_data == emc1402)
+		data->groups[1] = &emc1402_alarm_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   data->groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(&client->dev, "%s Thermal chip found\n", id->name);
+	return 0;
+}
+
+static const unsigned short emc1403_address_list[] = {
+	0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END
+};
+
+/* Last digit of chip name indicates number of channels */
+static const struct i2c_device_id emc1403_idtable[] = {
+	{ "emc1402", emc1402 },
+	{ "emc1403", emc1403 },
+	{ "emc1404", emc1404 },
+	{ "emc1412", emc1402 },
+	{ "emc1413", emc1403 },
+	{ "emc1414", emc1404 },
+	{ "emc1422", emc1402 },
+	{ "emc1423", emc1403 },
+	{ "emc1424", emc1404 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
+
+static struct i2c_driver sensor_emc1403 = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "emc1403",
+	},
+	.detect = emc1403_detect,
+	.probe = emc1403_probe,
+	.id_table = emc1403_idtable,
+	.address_list = emc1403_address_list,
+};
+
+module_i2c_driver(sensor_emc1403);
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("emc1403 Thermal Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
new file mode 100644
index 0000000..952fe69
--- /dev/null
+++ b/drivers/hwmon/emc2103.c
@@ -0,0 +1,693 @@
+/*
+ * emc2103.c - Support for SMSC EMC2103
+ * Copyright (c) 2010 SMSC
+ *
+ * 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>
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x2E, I2C_CLIENT_END };
+
+static const u8 REG_TEMP[4] = { 0x00, 0x02, 0x04, 0x06 };
+static const u8 REG_TEMP_MIN[4] = { 0x3c, 0x38, 0x39, 0x3a };
+static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 };
+
+#define REG_CONF1		0x20
+#define REG_TEMP_MAX_ALARM	0x24
+#define REG_TEMP_MIN_ALARM	0x25
+#define REG_FAN_CONF1		0x42
+#define REG_FAN_TARGET_LO	0x4c
+#define REG_FAN_TARGET_HI	0x4d
+#define REG_FAN_TACH_HI		0x4e
+#define REG_FAN_TACH_LO		0x4f
+#define REG_PRODUCT_ID		0xfd
+#define REG_MFG_ID		0xfe
+
+/* equation 4 from datasheet: rpm = (3932160 * multipler) / count */
+#define FAN_RPM_FACTOR		3932160
+
+/*
+ * 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes
+ * in anti-parallel mode, and in this configuration both can be read
+ * independently (so we have 4 temperature inputs).  The device can't
+ * detect if it's connected in this mode, so we have to manually enable
+ * it.  Default is to leave the device in the state it's already in (-1).
+ * This parameter allows APD mode to be optionally forced on or off
+ */
+static int apd = -1;
+module_param(apd, bint, 0);
+MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode");
+
+struct temperature {
+	s8	degrees;
+	u8	fraction;	/* 0-7 multiples of 0.125 */
+};
+
+struct emc2103_data {
+	struct i2c_client	*client;
+	const struct		attribute_group *groups[4];
+	struct mutex		update_lock;
+	bool			valid;		/* registers are valid */
+	bool			fan_rpm_control;
+	int			temp_count;	/* num of temp sensors */
+	unsigned long		last_updated;	/* in jiffies */
+	struct temperature	temp[4];	/* internal + 3 external */
+	s8			temp_min[4];	/* no fractional part */
+	s8			temp_max[4];    /* no fractional part */
+	u8			temp_min_alarm;
+	u8			temp_max_alarm;
+	u8			fan_multiplier;
+	u16			fan_tach;
+	u16			fan_target;
+};
+
+static int read_u8_from_i2c(struct i2c_client *client, u8 i2c_reg, u8 *output)
+{
+	int status = i2c_smbus_read_byte_data(client, i2c_reg);
+	if (status < 0) {
+		dev_warn(&client->dev, "reg 0x%02x, err %d\n",
+			i2c_reg, status);
+	} else {
+		*output = status;
+	}
+	return status;
+}
+
+static void read_temp_from_i2c(struct i2c_client *client, u8 i2c_reg,
+			       struct temperature *temp)
+{
+	u8 degrees, fractional;
+
+	if (read_u8_from_i2c(client, i2c_reg, &degrees) < 0)
+		return;
+
+	if (read_u8_from_i2c(client, i2c_reg + 1, &fractional) < 0)
+		return;
+
+	temp->degrees = degrees;
+	temp->fraction = (fractional & 0xe0) >> 5;
+}
+
+static void read_fan_from_i2c(struct i2c_client *client, u16 *output,
+			      u8 hi_addr, u8 lo_addr)
+{
+	u8 high_byte, lo_byte;
+
+	if (read_u8_from_i2c(client, hi_addr, &high_byte) < 0)
+		return;
+
+	if (read_u8_from_i2c(client, lo_addr, &lo_byte) < 0)
+		return;
+
+	*output = ((u16)high_byte << 5) | (lo_byte >> 3);
+}
+
+static void write_fan_target_to_i2c(struct i2c_client *client, u16 new_target)
+{
+	u8 high_byte = (new_target & 0x1fe0) >> 5;
+	u8 low_byte = (new_target & 0x001f) << 3;
+	i2c_smbus_write_byte_data(client, REG_FAN_TARGET_LO, low_byte);
+	i2c_smbus_write_byte_data(client, REG_FAN_TARGET_HI, high_byte);
+}
+
+static void read_fan_config_from_i2c(struct i2c_client *client)
+
+{
+	struct emc2103_data *data = i2c_get_clientdata(client);
+	u8 conf1;
+
+	if (read_u8_from_i2c(client, REG_FAN_CONF1, &conf1) < 0)
+		return;
+
+	data->fan_multiplier = 1 << ((conf1 & 0x60) >> 5);
+	data->fan_rpm_control = (conf1 & 0x80) != 0;
+}
+
+static struct emc2103_data *emc2103_update_device(struct device *dev)
+{
+	struct emc2103_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int i;
+
+		for (i = 0; i < data->temp_count; i++) {
+			read_temp_from_i2c(client, REG_TEMP[i], &data->temp[i]);
+			read_u8_from_i2c(client, REG_TEMP_MIN[i],
+				&data->temp_min[i]);
+			read_u8_from_i2c(client, REG_TEMP_MAX[i],
+				&data->temp_max[i]);
+		}
+
+		read_u8_from_i2c(client, REG_TEMP_MIN_ALARM,
+			&data->temp_min_alarm);
+		read_u8_from_i2c(client, REG_TEMP_MAX_ALARM,
+			&data->temp_max_alarm);
+
+		read_fan_from_i2c(client, &data->fan_tach,
+			REG_FAN_TACH_HI, REG_FAN_TACH_LO);
+		read_fan_from_i2c(client, &data->fan_target,
+			REG_FAN_TARGET_HI, REG_FAN_TARGET_LO);
+		read_fan_config_from_i2c(client);
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int millidegrees = data->temp[nr].degrees * 1000
+		+ data->temp[nr].fraction * 125;
+	return sprintf(buf, "%d\n", millidegrees);
+}
+
+static ssize_t
+show_temp_min(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int millidegrees = data->temp_min[nr] * 1000;
+	return sprintf(buf, "%d\n", millidegrees);
+}
+
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int millidegrees = data->temp_max[nr] * 1000;
+	return sprintf(buf, "%d\n", millidegrees);
+}
+
+static ssize_t
+show_temp_fault(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	bool fault = (data->temp[nr].degrees == -128);
+	return sprintf(buf, "%d\n", fault ? 1 : 0);
+}
+
+static ssize_t
+show_temp_min_alarm(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	bool alarm = data->temp_min_alarm & (1 << nr);
+	return sprintf(buf, "%d\n", alarm ? 1 : 0);
+}
+
+static ssize_t
+show_temp_max_alarm(struct device *dev, struct device_attribute *da, char *buf)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = emc2103_update_device(dev);
+	bool alarm = data->temp_max_alarm & (1 << nr);
+	return sprintf(buf, "%d\n", alarm ? 1 : 0);
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+
+	int result = kstrtol(buf, 10, &val);
+	if (result < 0)
+		return result;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = val;
+	i2c_smbus_write_byte_data(client, REG_TEMP_MIN[nr], val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(da)->index;
+	struct emc2103_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+
+	int result = kstrtol(buf, 10, &val);
+	if (result < 0)
+		return result;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = val;
+	i2c_smbus_write_byte_data(client, REG_TEMP_MAX[nr], val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int rpm = 0;
+	if (data->fan_tach != 0)
+		rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach;
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int fan_div = 8 / data->fan_multiplier;
+	return sprintf(buf, "%d\n", fan_div);
+}
+
+/*
+ * Note: we also update the fan target here, because its value is
+ * determined in part by the fan clock divider.  This follows the principle
+ * of least surprise; the user doesn't expect the fan target to change just
+ * because the divider changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	struct i2c_client *client = data->client;
+	int new_range_bits, old_div = 8 / data->fan_multiplier;
+	long new_div;
+
+	int status = kstrtol(buf, 10, &new_div);
+	if (status < 0)
+		return status;
+
+	if (new_div == old_div) /* No change */
+		return count;
+
+	switch (new_div) {
+	case 1:
+		new_range_bits = 3;
+		break;
+	case 2:
+		new_range_bits = 2;
+		break;
+	case 4:
+		new_range_bits = 1;
+		break;
+	case 8:
+		new_range_bits = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+
+	status = i2c_smbus_read_byte_data(client, REG_FAN_CONF1);
+	if (status < 0) {
+		dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
+			REG_FAN_CONF1, status);
+		mutex_unlock(&data->update_lock);
+		return status;
+	}
+	status &= 0x9F;
+	status |= (new_range_bits << 5);
+	i2c_smbus_write_byte_data(client, REG_FAN_CONF1, status);
+
+	data->fan_multiplier = 8 / new_div;
+
+	/* update fan target if high byte is not disabled */
+	if ((data->fan_target & 0x1fe0) != 0x1fe0) {
+		u16 new_target = (data->fan_target * old_div) / new_div;
+		data->fan_target = min(new_target, (u16)0x1fff);
+		write_fan_target_to_i2c(client, data->fan_target);
+	}
+
+	/* invalidate data to force re-read from hardware */
+	data->valid = false;
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_fan_target(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	int rpm = 0;
+
+	/* high byte of 0xff indicates disabled so return 0 */
+	if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0))
+		rpm = (FAN_RPM_FACTOR * data->fan_multiplier)
+			/ data->fan_target;
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
+			      const char *buf, size_t count)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	struct i2c_client *client = data->client;
+	unsigned long rpm_target;
+
+	int result = kstrtoul(buf, 10, &rpm_target);
+	if (result < 0)
+		return result;
+
+	/* Datasheet states 16384 as maximum RPM target (table 3.2) */
+	rpm_target = clamp_val(rpm_target, 0, 16384);
+
+	mutex_lock(&data->update_lock);
+
+	if (rpm_target == 0)
+		data->fan_target = 0x1fff;
+	else
+		data->fan_target = clamp_val(
+			(FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
+			0, 0x1fff);
+
+	write_fan_target_to_i2c(client, data->fan_target);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_fan_fault(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	bool fault = ((data->fan_tach & 0x1fe0) == 0x1fe0);
+	return sprintf(buf, "%d\n", fault ? 1 : 0);
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct emc2103_data *data = emc2103_update_device(dev);
+	return sprintf(buf, "%d\n", data->fan_rpm_control ? 3 : 0);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da,
+			      const char *buf, size_t count)
+{
+	struct emc2103_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long new_value;
+	u8 conf_reg;
+
+	int result = kstrtol(buf, 10, &new_value);
+	if (result < 0)
+		return result;
+
+	mutex_lock(&data->update_lock);
+	switch (new_value) {
+	case 0:
+		data->fan_rpm_control = false;
+		break;
+	case 3:
+		data->fan_rpm_control = true;
+		break;
+	default:
+		count = -EINVAL;
+		goto err;
+	}
+
+	result = read_u8_from_i2c(client, REG_FAN_CONF1, &conf_reg);
+	if (result) {
+		count = result;
+		goto err;
+	}
+
+	if (data->fan_rpm_control)
+		conf_reg |= 0x80;
+	else
+		conf_reg &= ~0x80;
+
+	i2c_smbus_write_byte_data(client, REG_FAN_CONF1, conf_reg);
+err:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, show_temp_min,
+	set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
+	set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_temp_min_alarm,
+	NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm,
+	NULL, 0);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, show_temp_min,
+	set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+	set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm,
+	NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm,
+	NULL, 1);
+
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, show_temp_min,
+	set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+	set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm,
+	NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm,
+	NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, show_temp_min,
+	set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
+	set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_temp_min_alarm,
+	NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_temp_max_alarm,
+	NULL, 3);
+
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL);
+static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, set_fan_div);
+static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_fan_target,
+	set_fan_target);
+static DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL);
+
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+	set_pwm_enable);
+
+/* sensors present on all models */
+static struct attribute *emc2103_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&dev_attr_fan1_input.attr,
+	&dev_attr_fan1_div.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_fault.attr,
+	&dev_attr_pwm1_enable.attr,
+	NULL
+};
+
+/* extra temperature sensors only present on 2103-2 and 2103-4 */
+static struct attribute *emc2103_attributes_temp3[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	NULL
+};
+
+/* extra temperature sensors only present on 2103-2 and 2103-4 in APD mode */
+static struct attribute *emc2103_attributes_temp4[] = {
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group emc2103_group = {
+	.attrs = emc2103_attributes,
+};
+
+static const struct attribute_group emc2103_temp3_group = {
+	.attrs = emc2103_attributes_temp3,
+};
+
+static const struct attribute_group emc2103_temp4_group = {
+	.attrs = emc2103_attributes_temp4,
+};
+
+static int
+emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct emc2103_data *data;
+	struct device *hwmon_dev;
+	int status, idx = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* 2103-2 and 2103-4 have 3 external diodes, 2103-1 has 1 */
+	status = i2c_smbus_read_byte_data(client, REG_PRODUCT_ID);
+	if (status == 0x24) {
+		/* 2103-1 only has 1 external diode */
+		data->temp_count = 2;
+	} else {
+		/* 2103-2 and 2103-4 have 3 or 4 external diodes */
+		status = i2c_smbus_read_byte_data(client, REG_CONF1);
+		if (status < 0) {
+			dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
+				status);
+			return status;
+		}
+
+		/* detect current state of hardware */
+		data->temp_count = (status & 0x01) ? 4 : 3;
+
+		/* force APD state if module parameter is set */
+		if (apd == 0) {
+			/* force APD mode off */
+			data->temp_count = 3;
+			status &= ~(0x01);
+			i2c_smbus_write_byte_data(client, REG_CONF1, status);
+		} else if (apd == 1) {
+			/* force APD mode on */
+			data->temp_count = 4;
+			status |= 0x01;
+			i2c_smbus_write_byte_data(client, REG_CONF1, status);
+		}
+	}
+
+	/* sysfs hooks */
+	data->groups[idx++] = &emc2103_group;
+	if (data->temp_count >= 3)
+		data->groups[idx++] = &emc2103_temp3_group;
+	if (data->temp_count == 4)
+		data->groups[idx++] = &emc2103_temp4_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   data->groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(&client->dev, "%s: sensor '%s'\n",
+		 dev_name(hwmon_dev), client->name);
+
+	return 0;
+}
+
+static const struct i2c_device_id emc2103_ids[] = {
+	{ "emc2103", 0, },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, emc2103_ids);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int
+emc2103_detect(struct i2c_client *new_client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	int manufacturer, product;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	manufacturer = i2c_smbus_read_byte_data(new_client, REG_MFG_ID);
+	if (manufacturer != 0x5D)
+		return -ENODEV;
+
+	product = i2c_smbus_read_byte_data(new_client, REG_PRODUCT_ID);
+	if ((product != 0x24) && (product != 0x26))
+		return -ENODEV;
+
+	strlcpy(info->type, "emc2103", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static struct i2c_driver emc2103_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "emc2103",
+	},
+	.probe		= emc2103_probe,
+	.id_table	= emc2103_ids,
+	.detect		= emc2103_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(emc2103_driver);
+
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
+MODULE_DESCRIPTION("SMSC EMC2103 hwmon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
new file mode 100644
index 0000000..ada9071
--- /dev/null
+++ b/drivers/hwmon/emc6w201.c
@@ -0,0 +1,527 @@
+/*
+ * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201
+ * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
+ *
+ * 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>
+
+/*
+ * Addresses to scan
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/*
+ * The EMC6W201 registers
+ */
+
+#define EMC6W201_REG_IN(nr)		(0x20 + (nr))
+#define EMC6W201_REG_TEMP(nr)		(0x26 + (nr))
+#define EMC6W201_REG_FAN(nr)		(0x2C + (nr) * 2)
+#define EMC6W201_REG_COMPANY		0x3E
+#define EMC6W201_REG_VERSTEP		0x3F
+#define EMC6W201_REG_CONFIG		0x40
+#define EMC6W201_REG_IN_LOW(nr)		(0x4A + (nr) * 2)
+#define EMC6W201_REG_IN_HIGH(nr)	(0x4B + (nr) * 2)
+#define EMC6W201_REG_TEMP_LOW(nr)	(0x56 + (nr) * 2)
+#define EMC6W201_REG_TEMP_HIGH(nr)	(0x57 + (nr) * 2)
+#define EMC6W201_REG_FAN_MIN(nr)	(0x62 + (nr) * 2)
+
+enum subfeature { input, min, max };
+
+/*
+ * Per-device data
+ */
+
+struct emc6w201_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	u8 in[3][6];
+	s8 temp[3][6];
+	u16 fan[2][5];
+};
+
+/*
+ * Combine LSB and MSB registers in a single value
+ * Locking: must be called with data->update_lock held
+ */
+static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
+{
+	int lsb, msb;
+
+	lsb = i2c_smbus_read_byte_data(client, reg);
+	msb = i2c_smbus_read_byte_data(client, reg + 1);
+	if (unlikely(lsb < 0 || msb < 0)) {
+		dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+			16, "read", reg);
+		return 0xFFFF;	/* Arbitrary value */
+	}
+
+	return (msb << 8) | lsb;
+}
+
+/*
+ * Write 16-bit value to LSB and MSB registers
+ * Locking: must be called with data->update_lock held
+ */
+static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
+{
+	int err;
+
+	err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
+	if (likely(!err))
+		err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+	if (unlikely(err < 0))
+		dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+			16, "write", reg);
+
+	return err;
+}
+
+/* Read 8-bit value from register */
+static u8 emc6w201_read8(struct i2c_client *client, u8 reg)
+{
+	int val;
+
+	val = i2c_smbus_read_byte_data(client, reg);
+	if (unlikely(val < 0)) {
+		dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+			8, "read", reg);
+		return 0x00;	/* Arbitrary value */
+	}
+
+	return val;
+}
+
+/* Write 8-bit value to register */
+static int emc6w201_write8(struct i2c_client *client, u8 reg, u8 val)
+{
+	int err;
+
+	err = i2c_smbus_write_byte_data(client, reg, val);
+	if (unlikely(err < 0))
+		dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+			8, "write", reg);
+
+	return err;
+}
+
+static struct emc6w201_data *emc6w201_update_device(struct device *dev)
+{
+	struct emc6w201_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		for (nr = 0; nr < 6; nr++) {
+			data->in[input][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_IN(nr));
+			data->in[min][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_IN_LOW(nr));
+			data->in[max][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_IN_HIGH(nr));
+		}
+
+		for (nr = 0; nr < 6; nr++) {
+			data->temp[input][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_TEMP(nr));
+			data->temp[min][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_TEMP_LOW(nr));
+			data->temp[max][nr] =
+				emc6w201_read8(client,
+						EMC6W201_REG_TEMP_HIGH(nr));
+		}
+
+		for (nr = 0; nr < 5; nr++) {
+			data->fan[input][nr] =
+				emc6w201_read16(client,
+						EMC6W201_REG_FAN(nr));
+			data->fan[min][nr] =
+				emc6w201_read16(client,
+						EMC6W201_REG_FAN_MIN(nr));
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+static const s16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct emc6w201_data *data = emc6w201_update_device(dev);
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+	return sprintf(buf, "%u\n",
+		       (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
+		      const char *buf, size_t count)
+{
+	struct emc6w201_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int err;
+	long val;
+	u8 reg;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]);
+	reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr)
+			  : EMC6W201_REG_IN_HIGH(nr);
+
+	mutex_lock(&data->update_lock);
+	data->in[sf][nr] = clamp_val(val, 0, 255);
+	err = emc6w201_write8(client, reg, data->in[sf][nr]);
+	mutex_unlock(&data->update_lock);
+
+	return err < 0 ? err : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct emc6w201_data *data = emc6w201_update_device(dev);
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+	return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct emc6w201_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int err;
+	long val;
+	u8 reg;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val, 1000);
+	reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr)
+			  : EMC6W201_REG_TEMP_HIGH(nr);
+
+	mutex_lock(&data->update_lock);
+	data->temp[sf][nr] = clamp_val(val, -127, 127);
+	err = emc6w201_write8(client, reg, data->temp[sf][nr]);
+	mutex_unlock(&data->update_lock);
+
+	return err < 0 ? err : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct emc6w201_data *data = emc6w201_update_device(dev);
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	unsigned rpm;
+
+	if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF)
+		rpm = 0;
+	else
+		rpm = 5400000U / data->fan[sf][nr];
+
+	return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct emc6w201_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int sf = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int err;
+	unsigned long val;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val == 0) {
+		val = 0xFFFF;
+	} else {
+		val = DIV_ROUND_CLOSEST(5400000U, val);
+		val = clamp_val(val, 0, 0xFFFE);
+	}
+
+	mutex_lock(&data->update_lock);
+	data->fan[sf][nr] = val;
+	err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr),
+			       data->fan[sf][nr]);
+	mutex_unlock(&data->update_lock);
+
+	return err < 0 ? err : count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    0, min);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    0, max);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    1, min);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    1, max);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    2, min);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    2, max);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    3, min);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    3, max);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    4, min);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    4, max);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    5, min);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    5, max);
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, min);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, max);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, min);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, max);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, min);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, max);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, min);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, max);
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, min);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, max);
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(temp6_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, min);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, max);
+
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    0, min);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    1, min);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    2, min);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    3, min);
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    4, min);
+
+static struct attribute *emc6w201_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_min.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_min.dev_attr.attr,
+	&sensor_dev_attr_temp6_max.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_min.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(emc6w201);
+
+/*
+ * Driver interface
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int emc6w201_detect(struct i2c_client *client,
+			   struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int company, verstep, config;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Identification */
+	company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY);
+	if (company != 0x5C)
+		return -ENODEV;
+	verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP);
+	if (verstep < 0 || (verstep & 0xF0) != 0xB0)
+		return -ENODEV;
+	if ((verstep & 0x0F) > 2) {
+		dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n",
+			verstep & 0x0F);
+		return -ENODEV;
+	}
+
+	/* Check configuration */
+	config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
+	if (config < 0 || (config & 0xF4) != 0x04)
+		return -ENODEV;
+	if (!(config & 0x01)) {
+		dev_err(&client->dev, "Monitoring not enabled\n");
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "emc6w201", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int emc6w201_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct emc6w201_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct emc6w201_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   emc6w201_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id emc6w201_id[] = {
+	{ "emc6w201", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, emc6w201_id);
+
+static struct i2c_driver emc6w201_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "emc6w201",
+	},
+	.probe		= emc6w201_probe,
+	.id_table	= emc6w201_id,
+	.detect		= emc6w201_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(emc6w201_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
new file mode 100644
index 0000000..facd05c
--- /dev/null
+++ b/drivers/hwmon/f71805f.c
@@ -0,0 +1,1653 @@
+/*
+ * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O
+ *             chips integrated hardware monitoring features
+ * Copyright (C) 2005-2006  Jean Delvare <jdelvare@suse.de>
+ *
+ * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
+ * complete hardware monitoring features: voltage, fan and temperature
+ * sensors, and manual and automatic fan speed control.
+ *
+ * The F71872F/FG is almost the same, with two more voltages monitored,
+ * and 6 VID inputs.
+ *
+ * The F71806F/FG is essentially the same as the F71872F/FG. It even has
+ * the same chip ID, so the driver can't differentiate between.
+ *
+ * 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.
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "f71805f"
+enum kinds { f71805f, f71872f };
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define F71805F_LD_HWM		0x04
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_DEVREV		0x22	/* Device revision */
+#define SIO_REG_MANID		0x23	/* Fintek ID (2 bytes) */
+#define SIO_REG_FNSEL1		0x29	/* Multi Function Select 1 (F71872F) */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+
+#define SIO_FINTEK_ID		0x1934
+#define SIO_F71805F_ID		0x0406
+#define SIO_F71872F_ID		0x0341
+
+static inline int
+superio_inb(int base, int reg)
+{
+	outb(reg, base);
+	return inb(base + 1);
+}
+
+static int
+superio_inw(int base, int reg)
+{
+	int val;
+	outb(reg++, base);
+	val = inb(base + 1) << 8;
+	outb(reg, base);
+	val |= inb(base + 1);
+	return val;
+}
+
+static inline void
+superio_select(int base, int ld)
+{
+	outb(SIO_REG_LDSEL, base);
+	outb(ld, base + 1);
+}
+
+static inline void
+superio_enter(int base)
+{
+	outb(0x87, base);
+	outb(0x87, base);
+}
+
+static inline void
+superio_exit(int base)
+{
+	outb(0xaa, base);
+}
+
+/*
+ * ISA constants
+ */
+
+#define REGION_LENGTH		8
+#define ADDR_REG_OFFSET		5
+#define DATA_REG_OFFSET		6
+
+/*
+ * Registers
+ */
+
+/* in nr from 0 to 10 (8-bit values) */
+#define F71805F_REG_IN(nr)		(0x10 + (nr))
+#define F71805F_REG_IN_HIGH(nr)		((nr) < 10 ? 0x40 + 2 * (nr) : 0x2E)
+#define F71805F_REG_IN_LOW(nr)		((nr) < 10 ? 0x41 + 2 * (nr) : 0x2F)
+/* fan nr from 0 to 2 (12-bit values, two registers) */
+#define F71805F_REG_FAN(nr)		(0x20 + 2 * (nr))
+#define F71805F_REG_FAN_LOW(nr)		(0x28 + 2 * (nr))
+#define F71805F_REG_FAN_TARGET(nr)	(0x69 + 16 * (nr))
+#define F71805F_REG_FAN_CTRL(nr)	(0x60 + 16 * (nr))
+#define F71805F_REG_PWM_FREQ(nr)	(0x63 + 16 * (nr))
+#define F71805F_REG_PWM_DUTY(nr)	(0x6B + 16 * (nr))
+/* temp nr from 0 to 2 (8-bit values) */
+#define F71805F_REG_TEMP(nr)		(0x1B + (nr))
+#define F71805F_REG_TEMP_HIGH(nr)	(0x54 + 2 * (nr))
+#define F71805F_REG_TEMP_HYST(nr)	(0x55 + 2 * (nr))
+#define F71805F_REG_TEMP_MODE		0x01
+/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
+/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
+#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
+					(0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
+#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
+					(0xA4 + 0x10 * (pwmnr) + \
+						2 * (2 - (apnr)))
+
+#define F71805F_REG_START		0x00
+/* status nr from 0 to 2 */
+#define F71805F_REG_STATUS(nr)		(0x36 + (nr))
+
+/* individual register bits */
+#define FAN_CTRL_DC_MODE		0x10
+#define FAN_CTRL_LATCH_FULL		0x08
+#define FAN_CTRL_MODE_MASK		0x03
+#define FAN_CTRL_MODE_SPEED		0x00
+#define FAN_CTRL_MODE_TEMPERATURE	0x01
+#define FAN_CTRL_MODE_MANUAL		0x02
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct f71805f_auto_point {
+	u8 temp[3];
+	u16 fan[3];
+};
+
+struct f71805f_data {
+	unsigned short addr;
+	const char *name;
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	unsigned long last_limits;	/* In jiffies */
+
+	/* Register values */
+	u8 in[11];
+	u8 in_high[11];
+	u8 in_low[11];
+	u16 has_in;
+	u16 fan[3];
+	u16 fan_low[3];
+	u16 fan_target[3];
+	u8 fan_ctrl[3];
+	u8 pwm[3];
+	u8 pwm_freq[3];
+	u8 temp[3];
+	u8 temp_high[3];
+	u8 temp_hyst[3];
+	u8 temp_mode;
+	unsigned long alarms;
+	struct f71805f_auto_point auto_points[3];
+};
+
+struct f71805f_sio_data {
+	enum kinds kind;
+	u8 fnsel1;
+};
+
+static inline long in_from_reg(u8 reg)
+{
+	return reg * 8;
+}
+
+/* The 2 least significant bits are not used */
+static inline u8 in_to_reg(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 2016)
+		return 0xfc;
+	return ((val + 16) / 32) << 2;
+}
+
+/* in0 is downscaled by a factor 2 internally */
+static inline long in0_from_reg(u8 reg)
+{
+	return reg * 16;
+}
+
+static inline u8 in0_to_reg(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 4032)
+		return 0xfc;
+	return ((val + 32) / 64) << 2;
+}
+
+/* The 4 most significant bits are not used */
+static inline long fan_from_reg(u16 reg)
+{
+	reg &= 0xfff;
+	if (!reg || reg == 0xfff)
+		return 0;
+	return 1500000 / reg;
+}
+
+static inline u16 fan_to_reg(long rpm)
+{
+	/*
+	 * If the low limit is set below what the chip can measure,
+	 * store the largest possible 12-bit value in the registers,
+	 * so that no alarm will ever trigger.
+	 */
+	if (rpm < 367)
+		return 0xfff;
+	return 1500000 / rpm;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+	unsigned long clock = (reg & 0x80) ? 48000000UL : 1000000UL;
+
+	reg &= 0x7f;
+	if (reg == 0)
+		reg++;
+	return clock / (reg << 8);
+}
+
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+	if (val >= 187500)	/* The highest we can do */
+		return 0x80;
+	if (val >= 1475)	/* Use 48 MHz clock */
+		return 0x80 | (48000000UL / (val << 8));
+	if (val < 31)		/* The lowest we can do */
+		return 0x7f;
+	else			/* Use 1 MHz clock */
+		return 1000000UL / (val << 8);
+}
+
+static inline int pwm_mode_from_reg(u8 reg)
+{
+	return !(reg & FAN_CTRL_DC_MODE);
+}
+
+static inline long temp_from_reg(u8 reg)
+{
+	return reg * 1000;
+}
+
+static inline u8 temp_to_reg(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 1000 * 0xff)
+		return 0xff;
+	return (val + 500) / 1000;
+}
+
+/*
+ * Device I/O access
+ */
+
+/* Must be called with data->update_lock held, except during initialization */
+static u8 f71805f_read8(struct f71805f_data *data, u8 reg)
+{
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	return inb(data->addr + DATA_REG_OFFSET);
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val)
+{
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	outb(val, data->addr + DATA_REG_OFFSET);
+}
+
+/*
+ * It is important to read the MSB first, because doing so latches the
+ * value of the LSB, so we are sure both bytes belong to the same value.
+ * Must be called with data->update_lock held, except during initialization
+ */
+static u16 f71805f_read16(struct f71805f_data *data, u8 reg)
+{
+	u16 val;
+
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	val = inb(data->addr + DATA_REG_OFFSET) << 8;
+	outb(++reg, data->addr + ADDR_REG_OFFSET);
+	val |= inb(data->addr + DATA_REG_OFFSET);
+
+	return val;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
+{
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	outb(val >> 8, data->addr + DATA_REG_OFFSET);
+	outb(++reg, data->addr + ADDR_REG_OFFSET);
+	outb(val & 0xff, data->addr + DATA_REG_OFFSET);
+}
+
+static struct f71805f_data *f71805f_update_device(struct device *dev)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	int nr, apnr;
+
+	mutex_lock(&data->update_lock);
+
+	/* Limit registers cache is refreshed after 60 seconds */
+	if (time_after(jiffies, data->last_updated + 60 * HZ)
+	 || !data->valid) {
+		for (nr = 0; nr < 11; nr++) {
+			if (!(data->has_in & (1 << nr)))
+				continue;
+			data->in_high[nr] = f71805f_read8(data,
+					    F71805F_REG_IN_HIGH(nr));
+			data->in_low[nr] = f71805f_read8(data,
+					   F71805F_REG_IN_LOW(nr));
+		}
+		for (nr = 0; nr < 3; nr++) {
+			data->fan_low[nr] = f71805f_read16(data,
+					    F71805F_REG_FAN_LOW(nr));
+			data->fan_target[nr] = f71805f_read16(data,
+					       F71805F_REG_FAN_TARGET(nr));
+			data->pwm_freq[nr] = f71805f_read8(data,
+					     F71805F_REG_PWM_FREQ(nr));
+		}
+		for (nr = 0; nr < 3; nr++) {
+			data->temp_high[nr] = f71805f_read8(data,
+					      F71805F_REG_TEMP_HIGH(nr));
+			data->temp_hyst[nr] = f71805f_read8(data,
+					      F71805F_REG_TEMP_HYST(nr));
+		}
+		data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
+		for (nr = 0; nr < 3; nr++) {
+			for (apnr = 0; apnr < 3; apnr++) {
+				data->auto_points[nr].temp[apnr] =
+					f71805f_read8(data,
+					F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
+									apnr));
+				data->auto_points[nr].fan[apnr] =
+					f71805f_read16(data,
+					F71805F_REG_PWM_AUTO_POINT_FAN(nr,
+								       apnr));
+			}
+		}
+
+		data->last_limits = jiffies;
+	}
+
+	/* Measurement registers cache is refreshed after 1 second */
+	if (time_after(jiffies, data->last_updated + HZ)
+	 || !data->valid) {
+		for (nr = 0; nr < 11; nr++) {
+			if (!(data->has_in & (1 << nr)))
+				continue;
+			data->in[nr] = f71805f_read8(data,
+				       F71805F_REG_IN(nr));
+		}
+		for (nr = 0; nr < 3; nr++) {
+			data->fan[nr] = f71805f_read16(data,
+					F71805F_REG_FAN(nr));
+			data->fan_ctrl[nr] = f71805f_read8(data,
+					     F71805F_REG_FAN_CTRL(nr));
+			data->pwm[nr] = f71805f_read8(data,
+					F71805F_REG_PWM_DUTY(nr));
+		}
+		for (nr = 0; nr < 3; nr++) {
+			data->temp[nr] = f71805f_read8(data,
+					 F71805F_REG_TEMP(nr));
+		}
+		data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0))
+			+ (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8)
+			+ (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs interface
+ */
+
+static ssize_t show_in0(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in0_from_reg(data->in[nr]));
+}
+
+static ssize_t show_in0_max(struct device *dev, struct device_attribute
+			    *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[nr]));
+}
+
+static ssize_t show_in0_min(struct device *dev, struct device_attribute
+			    *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[nr]));
+}
+
+static ssize_t set_in0_max(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_high[nr] = in0_to_reg(val);
+	f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_in0_min(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_low[nr] = in0_to_reg(val);
+	f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in_from_reg(data->in[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in_from_reg(data->in_high[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", in_from_reg(data->in_low[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute
+			  *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_high[nr] = in_to_reg(val);
+	f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute
+			  *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_low[nr] = in_to_reg(val);
+	f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", fan_from_reg(data->fan[nr]));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute
+			    *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr]));
+}
+
+static ssize_t show_fan_target(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", fan_from_reg(data->fan_target[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_low[nr] = fan_to_reg(val);
+	f71805f_write16(data, F71805F_REG_FAN_LOW(nr), data->fan_low[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute
+			      *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_target[nr] = fan_to_reg(val);
+	f71805f_write16(data, F71805F_REG_FAN_TARGET(nr),
+			data->fan_target[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%d\n", (int)data->pwm[nr]);
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	int mode;
+
+	switch (data->fan_ctrl[nr] & FAN_CTRL_MODE_MASK) {
+	case FAN_CTRL_MODE_SPEED:
+		mode = 3;
+		break;
+	case FAN_CTRL_MODE_TEMPERATURE:
+		mode = 2;
+		break;
+	default: /* MANUAL */
+		mode = 1;
+	}
+
+	return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%lu\n", pwm_freq_from_reg(data->pwm_freq[nr]));
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%d\n", pwm_mode_from_reg(data->fan_ctrl[nr]));
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = val;
+	f71805f_write8(data, F71805F_REG_PWM_DUTY(nr), data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct attribute *f71805f_attr_pwm[];
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+			      *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val < 1 || val > 3)
+		return -EINVAL;
+
+	if (val > 1) { /* Automatic mode, user can't set PWM value */
+		if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr],
+				     S_IRUGO))
+			dev_dbg(dev, "chmod -w pwm%d failed\n", nr + 1);
+	}
+
+	mutex_lock(&data->update_lock);
+	reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(nr))
+	    & ~FAN_CTRL_MODE_MASK;
+	switch (val) {
+	case 1:
+		reg |= FAN_CTRL_MODE_MANUAL;
+		break;
+	case 2:
+		reg |= FAN_CTRL_MODE_TEMPERATURE;
+		break;
+	case 3:
+		reg |= FAN_CTRL_MODE_SPEED;
+		break;
+	}
+	data->fan_ctrl[nr] = reg;
+	f71805f_write8(data, F71805F_REG_FAN_CTRL(nr), reg);
+	mutex_unlock(&data->update_lock);
+
+	if (val == 1) { /* Manual mode, user can set PWM value */
+		if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr],
+				     S_IRUGO | S_IWUSR))
+			dev_dbg(dev, "chmod +w pwm%d failed\n", nr + 1);
+	}
+
+	return count;
+}
+
+static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
+			    *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_freq[nr] = pwm_freq_to_reg(val);
+	f71805f_write8(data, F71805F_REG_PWM_FREQ(nr), data->pwm_freq[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+
+	return sprintf(buf, "%ld\n",
+		       temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+				       struct device_attribute *devattr,
+				       const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
+	f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
+		       data->auto_points[pwmnr].temp[apnr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_fan(struct device *dev,
+				       struct device_attribute *devattr,
+				       char *buf)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+
+	return sprintf(buf, "%ld\n",
+		       fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_fan(struct device *dev,
+				      struct device_attribute *devattr,
+				      const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
+	f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
+			data->auto_points[pwmnr].fan[apnr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg(data->temp_high[nr]));
+}
+
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg(data->temp_hyst[nr]));
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+
+	/* 3 is diode, 4 is thermistor */
+	return sprintf(buf, "%u\n", (data->temp_mode & (1 << nr)) ? 3 : 4);
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute
+			    *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_high[nr] = temp_to_reg(val);
+	f71805f_write8(data, F71805F_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute
+			     *devattr, const char *buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_hyst[nr] = temp_to_reg(val);
+	f71805f_write8(data, F71805F_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_alarms_in(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+
+	return sprintf(buf, "%lu\n", data->alarms & 0x7ff);
+}
+
+static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+
+	return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07);
+}
+
+static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
+				*devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+
+	return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct f71805f_data *data = f71805f_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int bitnr = attr->index;
+
+	return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1);
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+			  show_in0_max, set_in0_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
+			  show_in0_min, set_in0_min, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 4);
+static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 5);
+static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 6);
+static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 7);
+static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
+			  show_in_max, set_in_max, 8);
+static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
+			  show_in_min, set_in_min, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in0, NULL, 9);
+static SENSOR_DEVICE_ATTR(in9_max, S_IRUGO | S_IWUSR,
+			  show_in0_max, set_in0_max, 9);
+static SENSOR_DEVICE_ATTR(in9_min, S_IRUGO | S_IWUSR,
+			  show_in0_min, set_in0_min, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in0, NULL, 10);
+static SENSOR_DEVICE_ATTR(in10_max, S_IRUGO | S_IWUSR,
+			  show_in0_max, set_in0_max, 10);
+static SENSOR_DEVICE_ATTR(in10_min, S_IRUGO | S_IWUSR,
+			  show_in0_min, set_in0_min, 10);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+			  show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR,
+			  show_fan_target, set_fan_target, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+			  show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO | S_IWUSR,
+			  show_fan_target, set_fan_target, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+			  show_fan_min, set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan3_target, S_IRUGO | S_IWUSR,
+			  show_fan_target, set_fan_target, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
+
+/*
+ * pwm (value) files are created read-only, write permission is
+ * then added or removed dynamically as needed
+ */
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR,
+			  show_pwm_freq, set_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO | S_IWUSR,
+			  show_pwm_freq, set_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
+			  show_pwm_freq, set_pwm_freq, 2);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
+static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
+static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *f71805f_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_target.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_target.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_target.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_mode.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
+
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	&dev_attr_alarms_in.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&dev_attr_alarms_temp.attr,
+	&dev_attr_alarms_fan.attr,
+
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group f71805f_group = {
+	.attrs = f71805f_attributes,
+};
+
+static struct attribute *f71805f_attributes_optin[4][5] = {
+	{
+		&sensor_dev_attr_in4_input.dev_attr.attr,
+		&sensor_dev_attr_in4_max.dev_attr.attr,
+		&sensor_dev_attr_in4_min.dev_attr.attr,
+		&sensor_dev_attr_in4_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in8_input.dev_attr.attr,
+		&sensor_dev_attr_in8_max.dev_attr.attr,
+		&sensor_dev_attr_in8_min.dev_attr.attr,
+		&sensor_dev_attr_in8_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in9_input.dev_attr.attr,
+		&sensor_dev_attr_in9_max.dev_attr.attr,
+		&sensor_dev_attr_in9_min.dev_attr.attr,
+		&sensor_dev_attr_in9_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in10_input.dev_attr.attr,
+		&sensor_dev_attr_in10_max.dev_attr.attr,
+		&sensor_dev_attr_in10_min.dev_attr.attr,
+		&sensor_dev_attr_in10_alarm.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group f71805f_group_optin[4] = {
+	{ .attrs = f71805f_attributes_optin[0] },
+	{ .attrs = f71805f_attributes_optin[1] },
+	{ .attrs = f71805f_attributes_optin[2] },
+	{ .attrs = f71805f_attributes_optin[3] },
+};
+
+/*
+ * We don't include pwm_freq files in the arrays above, because they must be
+ * created conditionally (only if pwm_mode is 1 == PWM)
+ */
+static struct attribute *f71805f_attributes_pwm_freq[] = {
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group f71805f_group_pwm_freq = {
+	.attrs = f71805f_attributes_pwm_freq,
+};
+
+/* We also need an indexed access to pwmN files to toggle writability */
+static struct attribute *f71805f_attr_pwm[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/*
+ * Device registration and initialization
+ */
+
+static void f71805f_init_device(struct f71805f_data *data)
+{
+	u8 reg;
+	int i;
+
+	reg = f71805f_read8(data, F71805F_REG_START);
+	if ((reg & 0x41) != 0x01) {
+		pr_debug("Starting monitoring operations\n");
+		f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
+	}
+
+	/*
+	 * Fan monitoring can be disabled. If it is, we won't be polling
+	 * the register values, and won't create the related sysfs files.
+	 */
+	for (i = 0; i < 3; i++) {
+		data->fan_ctrl[i] = f71805f_read8(data,
+						  F71805F_REG_FAN_CTRL(i));
+		/*
+		 * Clear latch full bit, else "speed mode" fan speed control
+		 * doesn't work
+		 */
+		if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) {
+			data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL;
+			f71805f_write8(data, F71805F_REG_FAN_CTRL(i),
+				       data->fan_ctrl[i]);
+		}
+	}
+}
+
+static int f71805f_probe(struct platform_device *pdev)
+{
+	struct f71805f_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	struct f71805f_data *data;
+	struct resource *res;
+	int i, err;
+
+	static const char * const names[] = {
+		"f71805f",
+		"f71872f",
+	};
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2,
+				 DRVNAME)) {
+		dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)(res->start + ADDR_REG_OFFSET),
+			(unsigned long)(res->start + ADDR_REG_OFFSET + 1));
+		return -EBUSY;
+	}
+	data->addr = res->start;
+	data->name = names[sio_data->kind];
+	mutex_init(&data->update_lock);
+
+	platform_set_drvdata(pdev, data);
+
+	/* Some voltage inputs depend on chip model and configuration */
+	switch (sio_data->kind) {
+	case f71805f:
+		data->has_in = 0x1ff;
+		break;
+	case f71872f:
+		data->has_in = 0x6ef;
+		if (sio_data->fnsel1 & 0x01)
+			data->has_in |= (1 << 4); /* in4 */
+		if (sio_data->fnsel1 & 0x02)
+			data->has_in |= (1 << 8); /* in8 */
+		break;
+	}
+
+	/* Initialize the F71805F chip */
+	f71805f_init_device(data);
+
+	/* Register sysfs interface files */
+	err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group);
+	if (err)
+		return err;
+	if (data->has_in & (1 << 4)) { /* in4 */
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &f71805f_group_optin[0]);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->has_in & (1 << 8)) { /* in8 */
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &f71805f_group_optin[1]);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &f71805f_group_optin[2]);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &f71805f_group_optin[3]);
+		if (err)
+			goto exit_remove_files;
+	}
+	for (i = 0; i < 3; i++) {
+		/* If control mode is PWM, create pwm_freq file */
+		if (!(data->fan_ctrl[i] & FAN_CTRL_DC_MODE)) {
+			err = sysfs_create_file(&pdev->dev.kobj,
+						f71805f_attributes_pwm_freq[i]);
+			if (err)
+				goto exit_remove_files;
+		}
+		/* If PWM is in manual mode, add write permission */
+		if (data->fan_ctrl[i] & FAN_CTRL_MODE_MANUAL) {
+			err = sysfs_chmod_file(&pdev->dev.kobj,
+					       f71805f_attr_pwm[i],
+					       S_IRUGO | S_IWUSR);
+			if (err) {
+				dev_err(&pdev->dev, "chmod +w pwm%d failed\n",
+					i + 1);
+				goto exit_remove_files;
+			}
+		}
+	}
+
+	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_remove_files;
+	}
+
+	return 0;
+
+exit_remove_files:
+	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+	for (i = 0; i < 4; i++)
+		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
+	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+	return err;
+}
+
+static int f71805f_remove(struct platform_device *pdev)
+{
+	struct f71805f_data *data = platform_get_drvdata(pdev);
+	int i;
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+	for (i = 0; i < 4; i++)
+		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
+	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+
+	return 0;
+}
+
+static struct platform_driver f71805f_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= f71805f_probe,
+	.remove		= f71805f_remove,
+};
+
+static int __init f71805f_device_add(unsigned short address,
+				     const struct f71805f_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + REGION_LENGTH - 1,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	res.name = pdev->name;
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit_device_put;
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct f71805f_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init f71805f_find(int sioaddr, unsigned short *address,
+			       struct f71805f_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 devid;
+
+	static const char * const names[] = {
+		"F71805F/FG",
+		"F71872F/FG or F71806F/FG",
+	};
+
+	superio_enter(sioaddr);
+
+	devid = superio_inw(sioaddr, SIO_REG_MANID);
+	if (devid != SIO_FINTEK_ID)
+		goto exit;
+
+	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
+	switch (devid) {
+	case SIO_F71805F_ID:
+		sio_data->kind = f71805f;
+		break;
+	case SIO_F71872F_ID:
+		sio_data->kind = f71872f;
+		sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1);
+		break;
+	default:
+		pr_info("Unsupported Fintek device, skipping\n");
+		goto exit;
+	}
+
+	superio_select(sioaddr, F71805F_LD_HWM);
+	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+		pr_warn("Device not activated, skipping\n");
+		goto exit;
+	}
+
+	*address = superio_inw(sioaddr, SIO_REG_ADDR);
+	if (*address == 0) {
+		pr_warn("Base address not set, skipping\n");
+		goto exit;
+	}
+	*address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+
+	err = 0;
+	pr_info("Found %s chip at %#x, revision %u\n",
+		names[sio_data->kind], *address,
+		superio_inb(sioaddr, SIO_REG_DEVREV));
+
+exit:
+	superio_exit(sioaddr);
+	return err;
+}
+
+static int __init f71805f_init(void)
+{
+	int err;
+	unsigned short address;
+	struct f71805f_sio_data sio_data;
+
+	if (f71805f_find(0x2e, &address, &sio_data)
+	 && f71805f_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	err = platform_driver_register(&f71805f_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = f71805f_device_add(address, &sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&f71805f_driver);
+exit:
+	return err;
+}
+
+static void __exit f71805f_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&f71805f_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver");
+
+module_init(f71805f_init);
+module_exit(f71805f_exit);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
new file mode 100644
index 0000000..cb28e4b
--- /dev/null
+++ b/drivers/hwmon/f71882fg.c
@@ -0,0 +1,2811 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
+ *   Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, 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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+
+#define DRVNAME "f71882fg"
+
+#define SIO_F71858FG_LD_HWM	0x02	/* Hardware monitor logical device */
+#define SIO_F71882FG_LD_HWM	0x04	/* Hardware monitor logical device */
+#define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
+#define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_DEVREV		0x22	/* Device revision */
+#define SIO_REG_MANID		0x23	/* Fintek ID (2 bytes) */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+
+#define SIO_FINTEK_ID		0x1934	/* Manufacturers ID */
+#define SIO_F71808E_ID		0x0901	/* Chipset ID */
+#define SIO_F71808A_ID		0x1001	/* Chipset ID */
+#define SIO_F71858_ID		0x0507  /* Chipset ID */
+#define SIO_F71862_ID		0x0601	/* Chipset ID */
+#define SIO_F71868_ID		0x1106	/* Chipset ID */
+#define SIO_F71869_ID		0x0814	/* Chipset ID */
+#define SIO_F71869A_ID		0x1007	/* Chipset ID */
+#define SIO_F71882_ID		0x0541	/* Chipset ID */
+#define SIO_F71889_ID		0x0723	/* Chipset ID */
+#define SIO_F71889E_ID		0x0909	/* Chipset ID */
+#define SIO_F71889A_ID		0x1005	/* Chipset ID */
+#define SIO_F8000_ID		0x0581	/* Chipset ID */
+#define SIO_F81768D_ID		0x1210	/* Chipset ID */
+#define SIO_F81865_ID		0x0704	/* Chipset ID */
+#define SIO_F81866_ID		0x1010	/* Chipset ID */
+
+#define REGION_LENGTH		8
+#define ADDR_REG_OFFSET		5
+#define DATA_REG_OFFSET		6
+
+#define F71882FG_REG_IN_STATUS		0x12 /* f7188x only */
+#define F71882FG_REG_IN_BEEP		0x13 /* f7188x only */
+#define F71882FG_REG_IN(nr)		(0x20  + (nr))
+#define F71882FG_REG_IN1_HIGH		0x32 /* f7188x only */
+
+#define F81866_REG_IN_STATUS		0x16 /* F81866 only */
+#define F81866_REG_IN_BEEP			0x17 /* F81866 only */
+#define F81866_REG_IN1_HIGH		0x3a /* F81866 only */
+
+#define F71882FG_REG_FAN(nr)		(0xA0 + (16 * (nr)))
+#define F71882FG_REG_FAN_TARGET(nr)	(0xA2 + (16 * (nr)))
+#define F71882FG_REG_FAN_FULL_SPEED(nr)	(0xA4 + (16 * (nr)))
+#define F71882FG_REG_FAN_STATUS		0x92
+#define F71882FG_REG_FAN_BEEP		0x93
+
+#define F71882FG_REG_TEMP(nr)		(0x70 + 2 * (nr))
+#define F71882FG_REG_TEMP_OVT(nr)	(0x80 + 2 * (nr))
+#define F71882FG_REG_TEMP_HIGH(nr)	(0x81 + 2 * (nr))
+#define F71882FG_REG_TEMP_STATUS	0x62
+#define F71882FG_REG_TEMP_BEEP		0x63
+#define F71882FG_REG_TEMP_CONFIG	0x69
+#define F71882FG_REG_TEMP_HYST(nr)	(0x6C + (nr))
+#define F71882FG_REG_TEMP_TYPE		0x6B
+#define F71882FG_REG_TEMP_DIODE_OPEN	0x6F
+
+#define F71882FG_REG_PWM(nr)		(0xA3 + (16 * (nr)))
+#define F71882FG_REG_PWM_TYPE		0x94
+#define F71882FG_REG_PWM_ENABLE		0x96
+
+#define F71882FG_REG_FAN_HYST(nr)	(0x98 + (nr))
+
+#define F71882FG_REG_FAN_FAULT_T	0x9F
+#define F71882FG_FAN_NEG_TEMP_EN	0x20
+#define F71882FG_FAN_PROG_SEL		0x80
+
+#define F71882FG_REG_POINT_PWM(pwm, point)	(0xAA + (point) + (16 * (pwm)))
+#define F71882FG_REG_POINT_TEMP(pwm, point)	(0xA6 + (point) + (16 * (pwm)))
+#define F71882FG_REG_POINT_MAPPING(nr)		(0xAF + 16 * (nr))
+
+#define	F71882FG_REG_START		0x01
+
+#define F71882FG_MAX_INS		11
+
+#define FAN_MIN_DETECT			366 /* Lowest detectable fanspeed */
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a,
+	f71882fg, f71889fg, f71889ed, f71889a, f8000, f81768d, f81865f,
+	f81866a};
+
+static const char *const f71882fg_names[] = {
+	"f71808e",
+	"f71808a",
+	"f71858fg",
+	"f71862fg",
+	"f71868a",
+	"f71869", /* Both f71869f and f71869e, reg. compatible and same id */
+	"f71869a",
+	"f71882fg",
+	"f71889fg", /* f81801u too, same id */
+	"f71889ed",
+	"f71889a",
+	"f8000",
+	"f81768d",
+	"f81865f",
+	"f81866a",
+};
+
+static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
+	[f71808e]	= { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0 },
+	[f71808a]	= { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0 },
+	[f71858fg]	= { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	[f71862fg]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71868a]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
+	[f71869]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71869a]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71882fg]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71889fg]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71889ed]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f71889a]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
+	[f8000]		= { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	[f81768d]	= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+	[f81865f]	= { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+	[f81866a]	= { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
+};
+
+static const char f71882fg_has_in1_alarm[] = {
+	[f71808e]	= 0,
+	[f71808a]	= 0,
+	[f71858fg]	= 0,
+	[f71862fg]	= 0,
+	[f71868a]	= 0,
+	[f71869]	= 0,
+	[f71869a]	= 0,
+	[f71882fg]	= 1,
+	[f71889fg]	= 1,
+	[f71889ed]	= 1,
+	[f71889a]	= 1,
+	[f8000]		= 0,
+	[f81768d]	= 1,
+	[f81865f]	= 1,
+	[f81866a]	= 1,
+};
+
+static const char f71882fg_fan_has_beep[] = {
+	[f71808e]	= 0,
+	[f71808a]	= 0,
+	[f71858fg]	= 0,
+	[f71862fg]	= 1,
+	[f71868a]	= 1,
+	[f71869]	= 1,
+	[f71869a]	= 1,
+	[f71882fg]	= 1,
+	[f71889fg]	= 1,
+	[f71889ed]	= 1,
+	[f71889a]	= 1,
+	[f8000]		= 0,
+	[f81768d]	= 1,
+	[f81865f]	= 1,
+	[f81866a]	= 1,
+};
+
+static const char f71882fg_nr_fans[] = {
+	[f71808e]	= 3,
+	[f71808a]	= 2, /* +1 fan which is monitor + simple pwm only */
+	[f71858fg]	= 3,
+	[f71862fg]	= 3,
+	[f71868a]	= 3,
+	[f71869]	= 3,
+	[f71869a]	= 3,
+	[f71882fg]	= 4,
+	[f71889fg]	= 3,
+	[f71889ed]	= 3,
+	[f71889a]	= 3,
+	[f8000]		= 3, /* +1 fan which is monitor only */
+	[f81768d]	= 3,
+	[f81865f]	= 2,
+	[f81866a]	= 3,
+};
+
+static const char f71882fg_temp_has_beep[] = {
+	[f71808e]	= 0,
+	[f71808a]	= 1,
+	[f71858fg]	= 0,
+	[f71862fg]	= 1,
+	[f71868a]	= 1,
+	[f71869]	= 1,
+	[f71869a]	= 1,
+	[f71882fg]	= 1,
+	[f71889fg]	= 1,
+	[f71889ed]	= 1,
+	[f71889a]	= 1,
+	[f8000]		= 0,
+	[f81768d]	= 1,
+	[f81865f]	= 1,
+	[f81866a]	= 1,
+};
+
+static const char f71882fg_nr_temps[] = {
+	[f71808e]	= 2,
+	[f71808a]	= 2,
+	[f71858fg]	= 3,
+	[f71862fg]	= 3,
+	[f71868a]	= 3,
+	[f71869]	= 3,
+	[f71869a]	= 3,
+	[f71882fg]	= 3,
+	[f71889fg]	= 3,
+	[f71889ed]	= 3,
+	[f71889a]	= 3,
+	[f8000]		= 3,
+	[f81768d]	= 3,
+	[f81865f]	= 2,
+	[f81866a]	= 3,
+};
+
+static struct platform_device *f71882fg_pdev;
+
+/* Super-I/O Function prototypes */
+static inline int superio_inb(int base, int reg);
+static inline int superio_inw(int base, int reg);
+static inline int superio_enter(int base);
+static inline void superio_select(int base, int ld);
+static inline void superio_exit(int base);
+
+struct f71882fg_sio_data {
+	enum chips type;
+};
+
+struct f71882fg_data {
+	unsigned short addr;
+	enum chips type;
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	int temp_start;			/* temp numbering start (0 or 1) */
+	char valid;			/* !=0 if following fields are valid */
+	char auto_point_temp_signed;
+	unsigned long last_updated;	/* In jiffies */
+	unsigned long last_limits;	/* In jiffies */
+
+	/* Register Values */
+	u8	in[F71882FG_MAX_INS];
+	u8	in1_max;
+	u8	in_status;
+	u8	in_beep;
+	u16	fan[4];
+	u16	fan_target[4];
+	u16	fan_full_speed[4];
+	u8	fan_status;
+	u8	fan_beep;
+	/*
+	 * Note: all models have max 3 temperature channels, but on some
+	 * they are addressed as 0-2 and on others as 1-3, so for coding
+	 * convenience we reserve space for 4 channels
+	 */
+	u16	temp[4];
+	u8	temp_ovt[4];
+	u8	temp_high[4];
+	u8	temp_hyst[2]; /* 2 hysts stored per reg */
+	u8	temp_type[4];
+	u8	temp_status;
+	u8	temp_beep;
+	u8	temp_diode_open;
+	u8	temp_config;
+	u8	pwm[4];
+	u8	pwm_enable;
+	u8	pwm_auto_point_hyst[2];
+	u8	pwm_auto_point_mapping[4];
+	u8	pwm_auto_point_pwm[4][5];
+	s8	pwm_auto_point_temp[4][4];
+};
+
+/* Sysfs in */
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+	char *buf);
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+/* Sysfs Fan */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+	char *buf);
+static ssize_t show_fan_full_speed(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_fan_full_speed(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+/* Sysfs Temp */
+static ssize_t show_temp(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count);
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf);
+/* PWM and Auto point control */
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+	char *buf);
+static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
+	const char *buf, size_t count);
+static ssize_t show_simple_pwm(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_simple_pwm(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_enable(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_enable(struct device *dev,
+	struct device_attribute	*devattr, const char *buf, size_t count);
+static ssize_t show_pwm_interpolate(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_interpolate(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_channel(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_channel(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_pwm(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+	struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_temp(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count);
+/* Sysfs misc */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+	char *buf);
+
+static int f71882fg_probe(struct platform_device *pdev);
+static int f71882fg_remove(struct platform_device *pdev);
+
+static struct platform_driver f71882fg_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= f71882fg_probe,
+	.remove		= f71882fg_remove,
+};
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+/*
+ * Temp attr for the f71858fg, the f71858fg is special as it has its
+ * temperature indexes start at 0 (the others start at 1)
+ */
+static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+	SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 0),
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 0),
+	SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 0),
+	SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 0),
+	SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+	SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 1),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 1),
+	SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 1),
+	SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 1),
+	SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+	SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 2),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 2),
+	SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+	SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 2),
+	SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 2),
+	SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+	SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+};
+
+/* Temp attr for the standard models */
+static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
+	SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 1),
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 1),
+	/*
+	 * Should really be temp1_max_alarm, but older versions did not handle
+	 * the max and crit alarms separately and lm_sensors v2 depends on the
+	 * presence of temp#_alarm files. The same goes for temp2/3 _alarm.
+	 */
+	SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+	SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 1),
+	SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 1),
+	SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+	SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+	SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+}, {
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 2),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 2),
+	/* Should be temp2_max_alarm, see temp1_alarm note */
+	SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+	SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 2),
+	SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 2),
+	SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+	SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
+	SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+}, {
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 3),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 3),
+	/* Should be temp3_max_alarm, see temp1_alarm note */
+	SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
+	SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 3),
+	SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 3),
+	SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
+	SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
+	SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
+} };
+
+/* Temp attr for models which can beep on temp alarm */
+static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
+	SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 1),
+	SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 5),
+}, {
+	SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 2),
+	SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 6),
+}, {
+	SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 3),
+	SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 7),
+} };
+
+static struct sensor_device_attribute_2 f81866_temp_beep_attr[3][2] = { {
+	SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 0),
+	SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 4),
+}, {
+	SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 1),
+	SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 5),
+}, {
+	SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 2),
+	SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+		store_temp_beep, 0, 6),
+} };
+
+/*
+ * Temp attr for the f8000
+ * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
+ * is used as hysteresis value to clear alarms
+ * Also like the f71858fg its temperature indexes start at 0
+ */
+static struct sensor_device_attribute_2 f8000_temp_attr[] = {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+	SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 0),
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 0),
+	SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+	SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 1),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 1),
+	SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+	SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 2),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 2),
+	SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+	SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+};
+
+/* in attr for all models */
+static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
+	SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+	SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+	SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+	SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
+	SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
+	SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
+	SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
+	SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
+	SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
+	SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9),
+	SENSOR_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 0, 10),
+};
+
+/* For models with in1 alarm capability */
+static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
+	SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
+		0, 1),
+	SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
+		0, 1),
+	SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
+};
+
+/* Fan / PWM attr common to all models */
+static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
+	SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
+	SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
+		      show_fan_full_speed,
+		      store_fan_full_speed, 0, 0),
+	SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
+	SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+		      store_pwm_enable, 0, 0),
+	SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
+		      show_pwm_interpolate, store_pwm_interpolate, 0, 0),
+}, {
+	SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
+	SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
+		      show_fan_full_speed,
+		      store_fan_full_speed, 0, 1),
+	SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
+	SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
+	SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+		      store_pwm_enable, 0, 1),
+	SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
+		      show_pwm_interpolate, store_pwm_interpolate, 0, 1),
+}, {
+	SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+	SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
+		      show_fan_full_speed,
+		      store_fan_full_speed, 0, 2),
+	SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+	SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
+	SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+		      store_pwm_enable, 0, 2),
+	SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
+		      show_pwm_interpolate, store_pwm_interpolate, 0, 2),
+}, {
+	SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+	SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
+		      show_fan_full_speed,
+		      store_fan_full_speed, 0, 3),
+	SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
+	SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
+	SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+		      store_pwm_enable, 0, 3),
+	SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
+		      show_pwm_interpolate, store_pwm_interpolate, 0, 3),
+} };
+
+/* Attr for the third fan of the f71808a, which only has manual pwm */
+static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
+	SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+	SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+	SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
+		      show_simple_pwm, store_simple_pwm, 0, 2),
+};
+
+/* Attr for models which can beep on Fan alarm */
+static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
+	SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 0),
+	SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 1),
+	SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 2),
+	SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 3),
+};
+
+/*
+ * PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
+ * standard models
+ */
+static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
+	SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+}, {
+	SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+}, {
+	SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+} };
+
+/*
+ * PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
+ * pwm setting when the temperature is above the pwmX_auto_point1_temp can be
+ * programmed instead of being hardcoded to 0xff
+ */
+static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { {
+	SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 0),
+	SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+}, {
+	SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 1),
+	SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+}, {
+	SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 2),
+	SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+} };
+
+/* PWM attr for the standard models */
+static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
+	SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 0),
+	SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 0),
+	SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 0),
+	SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 0),
+	SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 0),
+	SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 0),
+	SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 0),
+	SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 0),
+	SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 0),
+	SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+}, {
+	SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 1),
+	SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 1),
+	SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 1),
+	SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 1),
+	SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 1),
+	SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 1),
+	SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 1),
+	SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 1),
+	SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 1),
+	SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+}, {
+	SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 2),
+	SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 2),
+	SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 2),
+	SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 2),
+	SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 2),
+	SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 2),
+	SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 2),
+	SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 2),
+	SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
+	SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+}, {
+	SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 3),
+	SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 3),
+	SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 3),
+	SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 3),
+	SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 3),
+	SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 3),
+	SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 3),
+	SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 3),
+	SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 3),
+	SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 3),
+	SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 3),
+	SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 3),
+	SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 3),
+	SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 3),
+} };
+
+/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
+static struct sensor_device_attribute_2 f8000_fan_attr[] = {
+	SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+};
+
+/*
+ * PWM attr for the f8000, zones mapped to temp instead of to pwm!
+ * Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
+ * F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0
+ */
+static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { {
+	SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 0),
+	SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 2),
+	SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 2),
+	SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 2),
+	SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 2),
+	SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 2),
+	SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 2),
+	SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 2),
+	SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 2),
+	SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 2),
+	SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 2),
+	SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 2),
+	SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
+	SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+}, {
+	SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 1),
+	SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 0),
+	SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 0),
+	SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 0),
+	SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 0),
+	SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 0),
+	SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 0),
+	SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 0),
+	SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 0),
+	SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 0),
+	SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 0),
+	SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 0),
+	SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 0),
+	SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+}, {
+	SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_channel,
+		      store_pwm_auto_point_channel, 0, 2),
+	SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      0, 1),
+	SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      1, 1),
+	SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      2, 1),
+	SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      3, 1),
+	SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+		      4, 1),
+	SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      0, 1),
+	SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      1, 1),
+	SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      2, 1),
+	SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+		      3, 1),
+	SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+		      show_pwm_auto_point_temp_hyst,
+		      store_pwm_auto_point_temp_hyst,
+		      0, 1),
+	SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 1, 1),
+	SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 2, 1),
+	SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
+		      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+} };
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+	outb(reg, base);
+	return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+	int val;
+	val  = superio_inb(base, reg) << 8;
+	val |= superio_inb(base, reg + 1);
+	return val;
+}
+
+static inline int superio_enter(int base)
+{
+	/* Don't step on other drivers' I/O space by accident */
+	if (!request_muxed_region(base, 2, DRVNAME)) {
+		pr_err("I/O address 0x%04x already in use\n", base);
+		return -EBUSY;
+	}
+
+	/* according to the datasheet the key must be send twice! */
+	outb(SIO_UNLOCK_KEY, base);
+	outb(SIO_UNLOCK_KEY, base);
+
+	return 0;
+}
+
+static inline void superio_select(int base, int ld)
+{
+	outb(SIO_REG_LDSEL, base);
+	outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+	outb(SIO_LOCK_KEY, base);
+	release_region(base, 2);
+}
+
+static inline int fan_from_reg(u16 reg)
+{
+	return reg ? (1500000 / reg) : 0;
+}
+
+static inline u16 fan_to_reg(int fan)
+{
+	return fan ? (1500000 / fan) : 0;
+}
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
+{
+	u8 val;
+
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	val = inb(data->addr + DATA_REG_OFFSET);
+
+	return val;
+}
+
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
+{
+	u16 val;
+
+	val  = f71882fg_read8(data, reg) << 8;
+	val |= f71882fg_read8(data, reg + 1);
+
+	return val;
+}
+
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
+{
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	outb(val, data->addr + DATA_REG_OFFSET);
+}
+
+static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
+{
+	f71882fg_write8(data, reg,     val >> 8);
+	f71882fg_write8(data, reg + 1, val & 0xff);
+}
+
+static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
+{
+	if (data->type == f71858fg)
+		return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
+	else
+		return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
+}
+
+static struct f71882fg_data *f71882fg_update_device(struct device *dev)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int nr_fans = f71882fg_nr_fans[data->type];
+	int nr_temps = f71882fg_nr_temps[data->type];
+	int nr, reg, point;
+
+	mutex_lock(&data->update_lock);
+
+	/* Update once every 60 seconds */
+	if (time_after(jiffies, data->last_limits + 60 * HZ) ||
+			!data->valid) {
+		if (f71882fg_has_in1_alarm[data->type]) {
+			if (data->type == f81866a) {
+				data->in1_max =
+					f71882fg_read8(data,
+						       F81866_REG_IN1_HIGH);
+				data->in_beep =
+					f71882fg_read8(data,
+						       F81866_REG_IN_BEEP);
+			} else {
+				data->in1_max =
+					f71882fg_read8(data,
+						       F71882FG_REG_IN1_HIGH);
+				data->in_beep =
+					f71882fg_read8(data,
+						       F71882FG_REG_IN_BEEP);
+			}
+		}
+
+		/* Get High & boundary temps*/
+		for (nr = data->temp_start; nr < nr_temps + data->temp_start;
+									nr++) {
+			data->temp_ovt[nr] = f71882fg_read8(data,
+						F71882FG_REG_TEMP_OVT(nr));
+			data->temp_high[nr] = f71882fg_read8(data,
+						F71882FG_REG_TEMP_HIGH(nr));
+		}
+
+		if (data->type != f8000) {
+			data->temp_hyst[0] = f71882fg_read8(data,
+						F71882FG_REG_TEMP_HYST(0));
+			data->temp_hyst[1] = f71882fg_read8(data,
+						F71882FG_REG_TEMP_HYST(1));
+		}
+		/* All but the f71858fg / f8000 have this register */
+		if ((data->type != f71858fg) && (data->type != f8000)) {
+			reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+			data->temp_type[1] = (reg & 0x02) ? 2 : 4;
+			data->temp_type[2] = (reg & 0x04) ? 2 : 4;
+			data->temp_type[3] = (reg & 0x08) ? 2 : 4;
+		}
+
+		if (f71882fg_fan_has_beep[data->type])
+			data->fan_beep = f71882fg_read8(data,
+						F71882FG_REG_FAN_BEEP);
+
+		if (f71882fg_temp_has_beep[data->type])
+			data->temp_beep = f71882fg_read8(data,
+						F71882FG_REG_TEMP_BEEP);
+
+		data->pwm_enable = f71882fg_read8(data,
+						  F71882FG_REG_PWM_ENABLE);
+		data->pwm_auto_point_hyst[0] =
+			f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
+		data->pwm_auto_point_hyst[1] =
+			f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
+
+		for (nr = 0; nr < nr_fans; nr++) {
+			data->pwm_auto_point_mapping[nr] =
+			    f71882fg_read8(data,
+					   F71882FG_REG_POINT_MAPPING(nr));
+
+			switch (data->type) {
+			default:
+				for (point = 0; point < 5; point++) {
+					data->pwm_auto_point_pwm[nr][point] =
+						f71882fg_read8(data,
+							F71882FG_REG_POINT_PWM
+							(nr, point));
+				}
+				for (point = 0; point < 4; point++) {
+					data->pwm_auto_point_temp[nr][point] =
+						f71882fg_read8(data,
+							F71882FG_REG_POINT_TEMP
+							(nr, point));
+				}
+				break;
+			case f71808e:
+			case f71869:
+				data->pwm_auto_point_pwm[nr][0] =
+					f71882fg_read8(data,
+						F71882FG_REG_POINT_PWM(nr, 0));
+				/* Fall through */
+			case f71862fg:
+				data->pwm_auto_point_pwm[nr][1] =
+					f71882fg_read8(data,
+						F71882FG_REG_POINT_PWM
+						(nr, 1));
+				data->pwm_auto_point_pwm[nr][4] =
+					f71882fg_read8(data,
+						F71882FG_REG_POINT_PWM
+						(nr, 4));
+				data->pwm_auto_point_temp[nr][0] =
+					f71882fg_read8(data,
+						F71882FG_REG_POINT_TEMP
+						(nr, 0));
+				data->pwm_auto_point_temp[nr][3] =
+					f71882fg_read8(data,
+						F71882FG_REG_POINT_TEMP
+						(nr, 3));
+				break;
+			}
+		}
+		data->last_limits = jiffies;
+	}
+
+	/* Update every second */
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		data->temp_status = f71882fg_read8(data,
+						F71882FG_REG_TEMP_STATUS);
+		data->temp_diode_open = f71882fg_read8(data,
+						F71882FG_REG_TEMP_DIODE_OPEN);
+		for (nr = data->temp_start; nr < nr_temps + data->temp_start;
+									nr++)
+			data->temp[nr] = f71882fg_read_temp(data, nr);
+
+		data->fan_status = f71882fg_read8(data,
+						F71882FG_REG_FAN_STATUS);
+		for (nr = 0; nr < nr_fans; nr++) {
+			data->fan[nr] = f71882fg_read16(data,
+						F71882FG_REG_FAN(nr));
+			data->fan_target[nr] =
+			    f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
+			data->fan_full_speed[nr] =
+			    f71882fg_read16(data,
+					    F71882FG_REG_FAN_FULL_SPEED(nr));
+			data->pwm[nr] =
+			    f71882fg_read8(data, F71882FG_REG_PWM(nr));
+		}
+		/* Some models have 1 more fan with limited capabilities */
+		if (data->type == f71808a) {
+			data->fan[2] = f71882fg_read16(data,
+						F71882FG_REG_FAN(2));
+			data->pwm[2] = f71882fg_read8(data,
+							F71882FG_REG_PWM(2));
+		}
+		if (data->type == f8000)
+			data->fan[3] = f71882fg_read16(data,
+						F71882FG_REG_FAN(3));
+
+		if (f71882fg_has_in1_alarm[data->type]) {
+			if (data->type == f81866a)
+				data->in_status = f71882fg_read8(data,
+						F81866_REG_IN_STATUS);
+
+			else
+				data->in_status = f71882fg_read8(data,
+						F71882FG_REG_IN_STATUS);
+		}
+
+		for (nr = 0; nr < F71882FG_MAX_INS; nr++)
+			if (f71882fg_has_in[data->type][nr])
+				data->in[nr] = f71882fg_read8(data,
+							F71882FG_REG_IN(nr));
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* Sysfs Interface */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int speed = fan_from_reg(data->fan[nr]);
+
+	if (speed == FAN_MIN_DETECT)
+		speed = 0;
+
+	return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_full_speed(struct device *dev,
+				   struct device_attribute *devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int speed = fan_from_reg(data->fan_full_speed[nr]);
+	return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t store_fan_full_speed(struct device *dev,
+				    struct device_attribute *devattr,
+				    const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, 23, 1500000);
+	val = fan_to_reg(val);
+
+	mutex_lock(&data->update_lock);
+	f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
+	data->fan_full_speed[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->fan_beep & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	unsigned long val;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
+	if (val)
+		data->fan_beep |= 1 << nr;
+	else
+		data->fan_beep &= ~(1 << nr);
+
+	f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->fan_status & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->in[nr] * 8);
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->in1_max * 8);
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 8;
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	if (data->type == f81866a)
+		f71882fg_write8(data, F81866_REG_IN1_HIGH, val);
+	else
+		f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
+	data->in1_max = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->in_beep & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	unsigned long val;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (data->type == f81866a)
+		data->in_beep = f71882fg_read8(data, F81866_REG_IN_BEEP);
+	else
+		data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+
+	if (val)
+		data->in_beep |= 1 << nr;
+	else
+		data->in_beep &= ~(1 << nr);
+
+	if (data->type == f81866a)
+		f71882fg_write8(data, F81866_REG_IN_BEEP, data->in_beep);
+	else
+		f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->in_status & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int sign, temp;
+
+	if (data->type == f71858fg) {
+		/* TEMP_TABLE_SEL 1 or 3 ? */
+		if (data->temp_config & 1) {
+			sign = data->temp[nr] & 0x0001;
+			temp = (data->temp[nr] >> 5) & 0x7ff;
+		} else {
+			sign = data->temp[nr] & 0x8000;
+			temp = (data->temp[nr] >> 5) & 0x3ff;
+		}
+		temp *= 125;
+		if (sign)
+			temp -= 128000;
+	} else
+		temp = data->temp[nr] * 1000;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 1000;
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
+	data->temp_high[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int temp_max_hyst;
+
+	mutex_lock(&data->update_lock);
+	if (nr & 1)
+		temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
+	else
+		temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
+	temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp_max_hyst);
+}
+
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	ssize_t ret = count;
+	u8 reg;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+
+	/* convert abs to relative and check */
+	data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
+	val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
+	val = data->temp_high[nr] - val;
+
+	/* convert value to register contents */
+	reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
+	if (nr & 1)
+		reg = (reg & 0x0f) | (val << 4);
+	else
+		reg = (reg & 0xf0) | val;
+	f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
+	data->temp_hyst[nr / 2] = reg;
+
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 1000;
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
+	data->temp_ovt[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int temp_crit_hyst;
+
+	mutex_lock(&data->update_lock);
+	if (nr & 1)
+		temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
+	else
+		temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
+	temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp_crit_hyst);
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->temp_type[nr]);
+}
+
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->temp_beep & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	unsigned long val;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
+	if (val)
+		data->temp_beep |= 1 << nr;
+	else
+		data->temp_beep &= ~(1 << nr);
+
+	f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->temp_status & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	if (data->temp_diode_open & (1 << nr))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int val, nr = to_sensor_dev_attr_2(devattr)->index;
+	mutex_lock(&data->update_lock);
+	if (data->pwm_enable & (1 << (2 * nr)))
+		/* PWM mode */
+		val = data->pwm[nr];
+	else {
+		/* RPM mode */
+		val = 255 * fan_from_reg(data->fan_target[nr])
+			/ fan_from_reg(data->fan_full_speed[nr]);
+	}
+	mutex_unlock(&data->update_lock);
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm(struct device *dev,
+			 struct device_attribute *devattr, const char *buf,
+			 size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+	if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
+	    (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
+		count = -EROFS;
+		goto leave;
+	}
+	if (data->pwm_enable & (1 << (2 * nr))) {
+		/* PWM mode */
+		f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+		data->pwm[nr] = val;
+	} else {
+		/* RPM mode */
+		int target, full_speed;
+		full_speed = f71882fg_read16(data,
+					     F71882FG_REG_FAN_FULL_SPEED(nr));
+		target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
+		f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
+		data->fan_target[nr] = target;
+		data->fan_full_speed[nr] = full_speed;
+	}
+leave:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_simple_pwm(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int val, nr = to_sensor_dev_attr_2(devattr)->index;
+
+	val = data->pwm[nr];
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_simple_pwm(struct device *dev,
+				struct device_attribute *devattr,
+				const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+	data->pwm[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	int result = 0;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	switch ((data->pwm_enable >> 2 * nr) & 3) {
+	case 0:
+	case 1:
+		result = 2; /* Normal auto mode */
+		break;
+	case 2:
+		result = 1; /* Manual mode */
+		break;
+	case 3:
+		if (data->type == f8000)
+			result = 3; /* Thermostat mode */
+		else
+			result = 1; /* Manual mode */
+		break;
+	}
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
+				*devattr, const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	/* Special case for F8000 pwm channel 3 which only does auto mode */
+	if (data->type == f8000 && nr == 2 && val != 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+	/* Special case for F8000 auto PWM mode / Thermostat mode */
+	if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
+		switch (val) {
+		case 2:
+			data->pwm_enable &= ~(2 << (2 * nr));
+			break;		/* Normal auto mode */
+		case 3:
+			data->pwm_enable |= 2 << (2 * nr);
+			break;		/* Thermostat mode */
+		default:
+			count = -EINVAL;
+			goto leave;
+		}
+	} else {
+		switch (val) {
+		case 1:
+			/* The f71858fg does not support manual RPM mode */
+			if (data->type == f71858fg &&
+			    ((data->pwm_enable >> (2 * nr)) & 1)) {
+				count = -EINVAL;
+				goto leave;
+			}
+			data->pwm_enable |= 2 << (2 * nr);
+			break;		/* Manual */
+		case 2:
+			data->pwm_enable &= ~(2 << (2 * nr));
+			break;		/* Normal auto mode */
+		default:
+			count = -EINVAL;
+			goto leave;
+		}
+	}
+	f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
+leave:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+				       struct device_attribute *devattr,
+				       char *buf)
+{
+	int result;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int pwm = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+
+	mutex_lock(&data->update_lock);
+	if (data->pwm_enable & (1 << (2 * pwm))) {
+		/* PWM mode */
+		result = data->pwm_auto_point_pwm[pwm][point];
+	} else {
+		/* RPM mode */
+		result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_pwm(struct device *dev,
+					struct device_attribute *devattr,
+					const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, pwm = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+	if (data->pwm_enable & (1 << (2 * pwm))) {
+		/* PWM mode */
+	} else {
+		/* RPM mode */
+		if (val < 29)	/* Prevent negative numbers */
+			val = 255;
+		else
+			val = (255 - val) * 32 / val;
+	}
+	f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
+	data->pwm_auto_point_pwm[pwm][point] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
+					     struct device_attribute *devattr,
+					     char *buf)
+{
+	int result = 0;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+
+	mutex_lock(&data->update_lock);
+	if (nr & 1)
+		result = data->pwm_auto_point_hyst[nr / 2] >> 4;
+	else
+		result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
+	result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
+					      struct device_attribute *devattr,
+					      const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+	u8 reg;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_auto_point_temp[nr][point] =
+		f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
+	val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
+			data->pwm_auto_point_temp[nr][point]);
+	val = data->pwm_auto_point_temp[nr][point] - val;
+
+	reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
+	if (nr & 1)
+		reg = (reg & 0x0f) | (val << 4);
+	else
+		reg = (reg & 0xf0) | val;
+
+	f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
+	data->pwm_auto_point_hyst[nr / 2] = reg;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_interpolate(struct device *dev,
+				    struct device_attribute *devattr, char *buf)
+{
+	int result;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_interpolate(struct device *dev,
+				     struct device_attribute *devattr,
+				     const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	unsigned long val;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_auto_point_mapping[nr] =
+		f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
+	if (val)
+		val = data->pwm_auto_point_mapping[nr] | (1 << 4);
+	else
+		val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
+	f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
+	data->pwm_auto_point_mapping[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_channel(struct device *dev,
+					   struct device_attribute *devattr,
+					   char *buf)
+{
+	int result;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int nr = to_sensor_dev_attr_2(devattr)->index;
+
+	result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
+		       data->temp_start);
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_channel(struct device *dev,
+					    struct device_attribute *devattr,
+					    const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, nr = to_sensor_dev_attr_2(devattr)->index;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	switch (val) {
+	case 1:
+		val = 0;
+		break;
+	case 2:
+		val = 1;
+		break;
+	case 4:
+		val = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+	val += data->temp_start;
+	mutex_lock(&data->update_lock);
+	data->pwm_auto_point_mapping[nr] =
+		f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
+	val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
+	f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
+	data->pwm_auto_point_mapping[nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	int result;
+	struct f71882fg_data *data = f71882fg_update_device(dev);
+	int pwm = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+
+	result = data->pwm_auto_point_temp[pwm][point];
+	return sprintf(buf, "%d\n", 1000 * result);
+}
+
+static ssize_t store_pwm_auto_point_temp(struct device *dev,
+					 struct device_attribute *devattr,
+					 const char *buf, size_t count)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	int err, pwm = to_sensor_dev_attr_2(devattr)->index;
+	int point = to_sensor_dev_attr_2(devattr)->nr;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 1000;
+
+	if (data->auto_point_temp_signed)
+		val = clamp_val(val, -128, 127);
+	else
+		val = clamp_val(val, 0, 127);
+
+	mutex_lock(&data->update_lock);
+	f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
+	data->pwm_auto_point_temp[pwm][point] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	struct f71882fg_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", f71882fg_names[data->type]);
+}
+
+static int f71882fg_create_sysfs_files(struct platform_device *pdev,
+	struct sensor_device_attribute_2 *attr, int count)
+{
+	int err, i;
+
+	for (i = 0; i < count; i++) {
+		err = device_create_file(&pdev->dev, &attr[i].dev_attr);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
+	struct sensor_device_attribute_2 *attr, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		device_remove_file(&pdev->dev, &attr[i].dev_attr);
+}
+
+static int f71882fg_create_fan_sysfs_files(
+	struct platform_device *pdev, int idx)
+{
+	struct f71882fg_data *data = platform_get_drvdata(pdev);
+	int err;
+
+	/* Sanity check the pwm setting */
+	err = 0;
+	switch (data->type) {
+	case f71858fg:
+		if (((data->pwm_enable >> (idx * 2)) & 3) == 3)
+			err = 1;
+		break;
+	case f71862fg:
+		if (((data->pwm_enable >> (idx * 2)) & 1) != 1)
+			err = 1;
+		break;
+	case f8000:
+		if (idx == 2)
+			err = data->pwm_enable & 0x20;
+		break;
+	default:
+		break;
+	}
+	if (err) {
+		dev_err(&pdev->dev,
+			"Invalid (reserved) pwm settings: 0x%02x, "
+			"skipping fan %d\n",
+			(data->pwm_enable >> (idx * 2)) & 3, idx + 1);
+		return 0; /* This is a non fatal condition */
+	}
+
+	err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[idx][0],
+					  ARRAY_SIZE(fxxxx_fan_attr[0]));
+	if (err)
+		return err;
+
+	if (f71882fg_fan_has_beep[data->type]) {
+		err = f71882fg_create_sysfs_files(pdev,
+						  &fxxxx_fan_beep_attr[idx],
+						  1);
+		if (err)
+			return err;
+	}
+
+	dev_info(&pdev->dev, "Fan: %d is in %s mode\n", idx + 1,
+		 (data->pwm_enable & (1 << (2 * idx))) ? "duty-cycle" : "RPM");
+
+	/* Check for unsupported auto pwm settings */
+	switch (data->type) {
+	case f71808e:
+	case f71808a:
+	case f71869:
+	case f71869a:
+	case f71889fg:
+	case f71889ed:
+	case f71889a:
+		data->pwm_auto_point_mapping[idx] =
+			f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(idx));
+		if ((data->pwm_auto_point_mapping[idx] & 0x80) ||
+		    (data->pwm_auto_point_mapping[idx] & 3) == 0) {
+			dev_warn(&pdev->dev,
+				 "Auto pwm controlled by raw digital "
+				 "data, disabling pwm auto_point "
+				 "sysfs attributes for fan %d\n", idx + 1);
+			return 0; /* This is a non fatal condition */
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (data->type) {
+	case f71862fg:
+		err = f71882fg_create_sysfs_files(pdev,
+					&f71862fg_auto_pwm_attr[idx][0],
+					ARRAY_SIZE(f71862fg_auto_pwm_attr[0]));
+		break;
+	case f71808e:
+	case f71869:
+		err = f71882fg_create_sysfs_files(pdev,
+					&f71869_auto_pwm_attr[idx][0],
+					ARRAY_SIZE(f71869_auto_pwm_attr[0]));
+		break;
+	case f8000:
+		err = f71882fg_create_sysfs_files(pdev,
+					&f8000_auto_pwm_attr[idx][0],
+					ARRAY_SIZE(f8000_auto_pwm_attr[0]));
+		break;
+	default:
+		err = f71882fg_create_sysfs_files(pdev,
+					&fxxxx_auto_pwm_attr[idx][0],
+					ARRAY_SIZE(fxxxx_auto_pwm_attr[0]));
+	}
+
+	return err;
+}
+
+static int f71882fg_probe(struct platform_device *pdev)
+{
+	struct f71882fg_data *data;
+	struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	int nr_fans = f71882fg_nr_fans[sio_data->type];
+	int nr_temps = f71882fg_nr_temps[sio_data->type];
+	int err, i;
+	int size;
+	u8 start_reg, reg;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	data->type = sio_data->type;
+	data->temp_start =
+	    (data->type == f71858fg || data->type == f8000 ||
+		data->type == f81866a) ? 0 : 1;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	start_reg = f71882fg_read8(data, F71882FG_REG_START);
+	if (start_reg & 0x04) {
+		dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
+		return -ENODEV;
+	}
+	if (!(start_reg & 0x03)) {
+		dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
+		return -ENODEV;
+	}
+
+	/* Register sysfs interface files */
+	err = device_create_file(&pdev->dev, &dev_attr_name);
+	if (err)
+		goto exit_unregister_sysfs;
+
+	if (start_reg & 0x01) {
+		switch (data->type) {
+		case f71858fg:
+			data->temp_config =
+				f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
+			if (data->temp_config & 0x10)
+				/*
+				 * The f71858fg temperature alarms behave as
+				 * the f8000 alarms in this mode
+				 */
+				err = f71882fg_create_sysfs_files(pdev,
+					f8000_temp_attr,
+					ARRAY_SIZE(f8000_temp_attr));
+			else
+				err = f71882fg_create_sysfs_files(pdev,
+					f71858fg_temp_attr,
+					ARRAY_SIZE(f71858fg_temp_attr));
+			break;
+		case f8000:
+			err = f71882fg_create_sysfs_files(pdev,
+					f8000_temp_attr,
+					ARRAY_SIZE(f8000_temp_attr));
+			break;
+		case f81866a:
+			err = f71882fg_create_sysfs_files(pdev,
+					f71858fg_temp_attr,
+					ARRAY_SIZE(f71858fg_temp_attr));
+			break;
+		default:
+			err = f71882fg_create_sysfs_files(pdev,
+				&fxxxx_temp_attr[0][0],
+				ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
+		}
+		if (err)
+			goto exit_unregister_sysfs;
+
+		if (f71882fg_temp_has_beep[data->type]) {
+			if (data->type == f81866a) {
+				size = ARRAY_SIZE(f81866_temp_beep_attr[0]);
+				err = f71882fg_create_sysfs_files(pdev,
+						&f81866_temp_beep_attr[0][0],
+						size * nr_temps);
+
+			} else {
+				size = ARRAY_SIZE(fxxxx_temp_beep_attr[0]);
+				err = f71882fg_create_sysfs_files(pdev,
+						&fxxxx_temp_beep_attr[0][0],
+						size * nr_temps);
+			}
+			if (err)
+				goto exit_unregister_sysfs;
+		}
+
+		for (i = 0; i < F71882FG_MAX_INS; i++) {
+			if (f71882fg_has_in[data->type][i]) {
+				err = device_create_file(&pdev->dev,
+						&fxxxx_in_attr[i].dev_attr);
+				if (err)
+					goto exit_unregister_sysfs;
+			}
+		}
+		if (f71882fg_has_in1_alarm[data->type]) {
+			err = f71882fg_create_sysfs_files(pdev,
+					fxxxx_in1_alarm_attr,
+					ARRAY_SIZE(fxxxx_in1_alarm_attr));
+			if (err)
+				goto exit_unregister_sysfs;
+		}
+	}
+
+	if (start_reg & 0x02) {
+		switch (data->type) {
+		case f71808e:
+		case f71808a:
+		case f71869:
+		case f71869a:
+			/* These always have signed auto point temps */
+			data->auto_point_temp_signed = 1;
+			/* Fall through to select correct fan/pwm reg bank! */
+		case f71889fg:
+		case f71889ed:
+		case f71889a:
+			reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
+			if (reg & F71882FG_FAN_NEG_TEMP_EN)
+				data->auto_point_temp_signed = 1;
+			/* Ensure banked pwm registers point to right bank */
+			reg &= ~F71882FG_FAN_PROG_SEL;
+			f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
+			break;
+		default:
+			break;
+		}
+
+		data->pwm_enable =
+			f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+
+		for (i = 0; i < nr_fans; i++) {
+			err = f71882fg_create_fan_sysfs_files(pdev, i);
+			if (err)
+				goto exit_unregister_sysfs;
+		}
+
+		/* Some types have 1 extra fan with limited functionality */
+		switch (data->type) {
+		case f71808a:
+			err = f71882fg_create_sysfs_files(pdev,
+					f71808a_fan3_attr,
+					ARRAY_SIZE(f71808a_fan3_attr));
+			break;
+		case f8000:
+			err = f71882fg_create_sysfs_files(pdev,
+					f8000_fan_attr,
+					ARRAY_SIZE(f8000_fan_attr));
+			break;
+		default:
+			break;
+		}
+		if (err)
+			goto exit_unregister_sysfs;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		data->hwmon_dev = NULL;
+		goto exit_unregister_sysfs;
+	}
+
+	return 0;
+
+exit_unregister_sysfs:
+	f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
+	return err; /* f71882fg_remove() also frees our data */
+}
+
+static int f71882fg_remove(struct platform_device *pdev)
+{
+	struct f71882fg_data *data = platform_get_drvdata(pdev);
+	int nr_fans = f71882fg_nr_fans[data->type];
+	int nr_temps = f71882fg_nr_temps[data->type];
+	int i;
+	u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
+
+	if (data->hwmon_dev)
+		hwmon_device_unregister(data->hwmon_dev);
+
+	device_remove_file(&pdev->dev, &dev_attr_name);
+
+	if (start_reg & 0x01) {
+		switch (data->type) {
+		case f71858fg:
+			if (data->temp_config & 0x10)
+				f71882fg_remove_sysfs_files(pdev,
+					f8000_temp_attr,
+					ARRAY_SIZE(f8000_temp_attr));
+			else
+				f71882fg_remove_sysfs_files(pdev,
+					f71858fg_temp_attr,
+					ARRAY_SIZE(f71858fg_temp_attr));
+			break;
+		case f8000:
+			f71882fg_remove_sysfs_files(pdev,
+					f8000_temp_attr,
+					ARRAY_SIZE(f8000_temp_attr));
+			break;
+		case f81866a:
+			f71882fg_remove_sysfs_files(pdev,
+					f71858fg_temp_attr,
+					ARRAY_SIZE(f71858fg_temp_attr));
+			break;
+		default:
+			f71882fg_remove_sysfs_files(pdev,
+				&fxxxx_temp_attr[0][0],
+				ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
+		}
+		if (f71882fg_temp_has_beep[data->type]) {
+			if (data->type == f81866a)
+				f71882fg_remove_sysfs_files(pdev,
+					&f81866_temp_beep_attr[0][0],
+					ARRAY_SIZE(f81866_temp_beep_attr[0])
+						* nr_temps);
+			else
+				f71882fg_remove_sysfs_files(pdev,
+					&fxxxx_temp_beep_attr[0][0],
+					ARRAY_SIZE(fxxxx_temp_beep_attr[0])
+						* nr_temps);
+		}
+
+		for (i = 0; i < F71882FG_MAX_INS; i++) {
+			if (f71882fg_has_in[data->type][i]) {
+				device_remove_file(&pdev->dev,
+						&fxxxx_in_attr[i].dev_attr);
+			}
+		}
+		if (f71882fg_has_in1_alarm[data->type]) {
+			f71882fg_remove_sysfs_files(pdev,
+					fxxxx_in1_alarm_attr,
+					ARRAY_SIZE(fxxxx_in1_alarm_attr));
+		}
+	}
+
+	if (start_reg & 0x02) {
+		f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
+				ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
+
+		if (f71882fg_fan_has_beep[data->type]) {
+			f71882fg_remove_sysfs_files(pdev,
+					fxxxx_fan_beep_attr, nr_fans);
+		}
+
+		switch (data->type) {
+		case f71808a:
+			f71882fg_remove_sysfs_files(pdev,
+				&fxxxx_auto_pwm_attr[0][0],
+				ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+			f71882fg_remove_sysfs_files(pdev,
+					f71808a_fan3_attr,
+					ARRAY_SIZE(f71808a_fan3_attr));
+			break;
+		case f71862fg:
+			f71882fg_remove_sysfs_files(pdev,
+				&f71862fg_auto_pwm_attr[0][0],
+				ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) *
+					nr_fans);
+			break;
+		case f71808e:
+		case f71869:
+			f71882fg_remove_sysfs_files(pdev,
+				&f71869_auto_pwm_attr[0][0],
+				ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans);
+			break;
+		case f8000:
+			f71882fg_remove_sysfs_files(pdev,
+					f8000_fan_attr,
+					ARRAY_SIZE(f8000_fan_attr));
+			f71882fg_remove_sysfs_files(pdev,
+				&f8000_auto_pwm_attr[0][0],
+				ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans);
+			break;
+		default:
+			f71882fg_remove_sysfs_files(pdev,
+				&fxxxx_auto_pwm_attr[0][0],
+				ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+		}
+	}
+	return 0;
+}
+
+static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
+{
+	u16 devid;
+	unsigned short address;
+	int err = superio_enter(sioaddr);
+	if (err)
+		return err;
+
+	devid = superio_inw(sioaddr, SIO_REG_MANID);
+	if (devid != SIO_FINTEK_ID) {
+		pr_debug("Not a Fintek device\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
+	switch (devid) {
+	case SIO_F71808E_ID:
+		sio_data->type = f71808e;
+		break;
+	case SIO_F71808A_ID:
+		sio_data->type = f71808a;
+		break;
+	case SIO_F71858_ID:
+		sio_data->type = f71858fg;
+		break;
+	case SIO_F71862_ID:
+		sio_data->type = f71862fg;
+		break;
+	case SIO_F71868_ID:
+		sio_data->type = f71868a;
+		break;
+	case SIO_F71869_ID:
+		sio_data->type = f71869;
+		break;
+	case SIO_F71869A_ID:
+		sio_data->type = f71869a;
+		break;
+	case SIO_F71882_ID:
+		sio_data->type = f71882fg;
+		break;
+	case SIO_F71889_ID:
+		sio_data->type = f71889fg;
+		break;
+	case SIO_F71889E_ID:
+		sio_data->type = f71889ed;
+		break;
+	case SIO_F71889A_ID:
+		sio_data->type = f71889a;
+		break;
+	case SIO_F8000_ID:
+		sio_data->type = f8000;
+		break;
+	case SIO_F81768D_ID:
+		sio_data->type = f81768d;
+		break;
+	case SIO_F81865_ID:
+		sio_data->type = f81865f;
+		break;
+	case SIO_F81866_ID:
+		sio_data->type = f81866a;
+		break;
+	default:
+		pr_info("Unsupported Fintek device: %04x\n",
+			(unsigned int)devid);
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (sio_data->type == f71858fg)
+		superio_select(sioaddr, SIO_F71858FG_LD_HWM);
+	else
+		superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+
+	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+		pr_warn("Device not activated\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	address = superio_inw(sioaddr, SIO_REG_ADDR);
+	if (address == 0) {
+		pr_warn("Base address not set\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+
+	err = address;
+	pr_info("Found %s chip at %#x, revision %d\n",
+		f71882fg_names[sio_data->type],	(unsigned int)address,
+		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
+exit:
+	superio_exit(sioaddr);
+	return err;
+}
+
+static int __init f71882fg_device_add(int address,
+				      const struct f71882fg_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + REGION_LENGTH - 1,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	f71882fg_pdev = platform_device_alloc(DRVNAME, address);
+	if (!f71882fg_pdev)
+		return -ENOMEM;
+
+	res.name = f71882fg_pdev->name;
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit_device_put;
+
+	err = platform_device_add_resources(f71882fg_pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(f71882fg_pdev, sio_data,
+				       sizeof(struct f71882fg_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(f71882fg_pdev);
+	if (err) {
+		pr_err("Device addition failed\n");
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(f71882fg_pdev);
+
+	return err;
+}
+
+static int __init f71882fg_init(void)
+{
+	int err;
+	int address;
+	struct f71882fg_sio_data sio_data;
+
+	memset(&sio_data, 0, sizeof(sio_data));
+
+	address = f71882fg_find(0x2e, &sio_data);
+	if (address < 0)
+		address = f71882fg_find(0x4e, &sio_data);
+	if (address < 0)
+		return address;
+
+	err = platform_driver_register(&f71882fg_driver);
+	if (err)
+		return err;
+
+	err = f71882fg_device_add(address, &sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&f71882fg_driver);
+	return err;
+}
+
+static void __exit f71882fg_exit(void)
+{
+	platform_device_unregister(f71882fg_pdev);
+	platform_driver_unregister(&f71882fg_driver);
+}
+
+MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(f71882fg_init);
+module_exit(f71882fg_exit);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
new file mode 100644
index 0000000..80c42be
--- /dev/null
+++ b/drivers/hwmon/f75375s.c
@@ -0,0 +1,925 @@
+/*
+ * f75375s.c - driver for the Fintek F75375/SP, F75373 and
+ *             F75387SG/RG hardware monitoring features
+ * Copyright (C) 2006-2007  Riku Voipio
+ *
+ * Datasheets available at:
+ *
+ * f75375:
+ * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf
+ *
+ * f75373:
+ * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf
+ *
+ * f75387:
+ * http://www.fintek.com.tw/files/productfiles/F75387_V027P.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/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/f75375s.h>
+#include <linux/slab.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips { f75373, f75375, f75387 };
+
+/* Fintek F75375 registers  */
+#define F75375_REG_CONFIG0		0x0
+#define F75375_REG_CONFIG1		0x1
+#define F75375_REG_CONFIG2		0x2
+#define F75375_REG_CONFIG3		0x3
+#define F75375_REG_ADDR			0x4
+#define F75375_REG_INTR			0x31
+#define F75375_CHIP_ID			0x5A
+#define F75375_REG_VERSION		0x5C
+#define F75375_REG_VENDOR		0x5D
+#define F75375_REG_FAN_TIMER		0x60
+
+#define F75375_REG_VOLT(nr)		(0x10 + (nr))
+#define F75375_REG_VOLT_HIGH(nr)	(0x20 + (nr) * 2)
+#define F75375_REG_VOLT_LOW(nr)		(0x21 + (nr) * 2)
+
+#define F75375_REG_TEMP(nr)		(0x14 + (nr))
+#define F75387_REG_TEMP11_LSB(nr)	(0x1a + (nr))
+#define F75375_REG_TEMP_HIGH(nr)	(0x28 + (nr) * 2)
+#define F75375_REG_TEMP_HYST(nr)	(0x29 + (nr) * 2)
+
+#define F75375_REG_FAN(nr)		(0x16 + (nr) * 2)
+#define F75375_REG_FAN_MIN(nr)		(0x2C + (nr) * 2)
+#define F75375_REG_FAN_FULL(nr)		(0x70 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_DUTY(nr)	(0x76 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_CLOCK(nr)	(0x7D + (nr) * 0x10)
+
+#define F75375_REG_FAN_EXP(nr)		(0x74 + (nr) * 0x10)
+#define F75375_REG_FAN_B_TEMP(nr, step)	((0xA0 + (nr) * 0x10) + (step))
+#define F75375_REG_FAN_B_SPEED(nr, step) \
+	((0xA5 + (nr) * 0x10) + (step) * 2)
+
+#define F75375_REG_PWM1_RAISE_DUTY	0x69
+#define F75375_REG_PWM2_RAISE_DUTY	0x6A
+#define F75375_REG_PWM1_DROP_DUTY	0x6B
+#define F75375_REG_PWM2_DROP_DUTY	0x6C
+
+#define F75375_FAN_CTRL_LINEAR(nr)	(4 + nr)
+#define F75387_FAN_CTRL_LINEAR(nr)	(1 + ((nr) * 4))
+#define FAN_CTRL_MODE(nr)		(4 + ((nr) * 2))
+#define F75387_FAN_DUTY_MODE(nr)	(2 + ((nr) * 4))
+#define F75387_FAN_MANU_MODE(nr)	((nr) * 4)
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct f75375_data {
+	unsigned short addr;
+	struct device *hwmon_dev;
+
+	const char *name;
+	int kind;
+	struct mutex update_lock; /* protect register access */
+	char valid;
+	unsigned long last_updated;	/* In jiffies */
+	unsigned long last_limits;	/* In jiffies */
+
+	/* Register values */
+	u8 in[4];
+	u8 in_max[4];
+	u8 in_min[4];
+	u16 fan[2];
+	u16 fan_min[2];
+	u16 fan_max[2];
+	u16 fan_target[2];
+	u8 fan_timer;
+	u8 pwm[2];
+	u8 pwm_mode[2];
+	u8 pwm_enable[2];
+	/*
+	 * f75387: For remote temperature reading, it uses signed 11-bit
+	 * values with LSB = 0.125 degree Celsius, left-justified in 16-bit
+	 * registers. For original 8-bit temp readings, the LSB just is 0.
+	 */
+	s16 temp11[2];
+	s8 temp_high[2];
+	s8 temp_max_hyst[2];
+};
+
+static int f75375_detect(struct i2c_client *client,
+			 struct i2c_board_info *info);
+static int f75375_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
+static int f75375_remove(struct i2c_client *client);
+
+static const struct i2c_device_id f75375_id[] = {
+	{ "f75373", f75373 },
+	{ "f75375", f75375 },
+	{ "f75387", f75387 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, f75375_id);
+
+static struct i2c_driver f75375_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "f75375",
+	},
+	.probe = f75375_probe,
+	.remove = f75375_remove,
+	.id_table = f75375_id,
+	.detect = f75375_detect,
+	.address_list = normal_i2c,
+};
+
+static inline int f75375_read8(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* in most cases, should be called while holding update_lock */
+static inline u16 f75375_read16(struct i2c_client *client, u8 reg)
+{
+	return (i2c_smbus_read_byte_data(client, reg) << 8)
+		| i2c_smbus_read_byte_data(client, reg + 1);
+}
+
+static inline void f75375_write8(struct i2c_client *client, u8 reg,
+		u8 value)
+{
+	i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline void f75375_write16(struct i2c_client *client, u8 reg,
+		u16 value)
+{
+	int err = i2c_smbus_write_byte_data(client, reg, (value >> 8));
+	if (err)
+		return;
+	i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
+}
+
+static void f75375_write_pwm(struct i2c_client *client, int nr)
+{
+	struct f75375_data *data = i2c_get_clientdata(client);
+	if (data->kind == f75387)
+		f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]);
+	else
+		f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+			      data->pwm[nr]);
+}
+
+static struct f75375_data *f75375_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	int nr;
+
+	mutex_lock(&data->update_lock);
+
+	/* Limit registers cache is refreshed after 60 seconds */
+	if (time_after(jiffies, data->last_limits + 60 * HZ)
+		|| !data->valid) {
+		for (nr = 0; nr < 2; nr++) {
+			data->temp_high[nr] =
+				f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
+			data->temp_max_hyst[nr] =
+				f75375_read8(client, F75375_REG_TEMP_HYST(nr));
+			data->fan_max[nr] =
+				f75375_read16(client, F75375_REG_FAN_FULL(nr));
+			data->fan_min[nr] =
+				f75375_read16(client, F75375_REG_FAN_MIN(nr));
+			data->fan_target[nr] =
+				f75375_read16(client, F75375_REG_FAN_EXP(nr));
+		}
+		for (nr = 0; nr < 4; nr++) {
+			data->in_max[nr] =
+				f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
+			data->in_min[nr] =
+				f75375_read8(client, F75375_REG_VOLT_LOW(nr));
+		}
+		data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
+		data->last_limits = jiffies;
+	}
+
+	/* Measurement registers cache is refreshed after 2 second */
+	if (time_after(jiffies, data->last_updated + 2 * HZ)
+		|| !data->valid) {
+		for (nr = 0; nr < 2; nr++) {
+			data->pwm[nr] =	f75375_read8(client,
+				F75375_REG_FAN_PWM_DUTY(nr));
+			/* assign MSB, therefore shift it by 8 bits */
+			data->temp11[nr] =
+				f75375_read8(client, F75375_REG_TEMP(nr)) << 8;
+			if (data->kind == f75387)
+				/* merge F75387's temperature LSB (11-bit) */
+				data->temp11[nr] |=
+					f75375_read8(client,
+						     F75387_REG_TEMP11_LSB(nr));
+			data->fan[nr] =
+				f75375_read16(client, F75375_REG_FAN(nr));
+		}
+		for (nr = 0; nr < 4; nr++)
+			data->in[nr] =
+				f75375_read8(client, F75375_REG_VOLT(nr));
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static inline u16 rpm_from_reg(u16 reg)
+{
+	if (reg == 0 || reg == 0xffff)
+		return 0;
+	return 1500000 / reg;
+}
+
+static inline u16 rpm_to_reg(int rpm)
+{
+	if (rpm < 367 || rpm > 0xffff)
+		return 0xffff;
+	return 1500000 / rpm;
+}
+
+static bool duty_mode_enabled(u8 pwm_enable)
+{
+	switch (pwm_enable) {
+	case 0: /* Manual, duty mode (full speed) */
+	case 1: /* Manual, duty mode */
+	case 4: /* Auto, duty mode */
+		return true;
+	case 2: /* Auto, speed mode */
+	case 3: /* Manual, speed mode */
+		return false;
+	default:
+		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable);
+		return true;
+	}
+}
+
+static bool auto_mode_enabled(u8 pwm_enable)
+{
+	switch (pwm_enable) {
+	case 0: /* Manual, duty mode (full speed) */
+	case 1: /* Manual, duty mode */
+	case 3: /* Manual, speed mode */
+		return false;
+	case 2: /* Auto, speed mode */
+	case 4: /* Auto, duty mode */
+		return true;
+	default:
+		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable);
+		return false;
+	}
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = rpm_to_reg(val);
+	f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (auto_mode_enabled(data->pwm_enable[nr]))
+		return -EINVAL;
+	if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr]))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->fan_target[nr] = rpm_to_reg(val);
+	f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (auto_mode_enabled(data->pwm_enable[nr]) ||
+	    !duty_mode_enabled(data->pwm_enable[nr]))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = clamp_val(val, 0, 255);
+	f75375_write_pwm(client, nr);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
+{
+	struct f75375_data *data = i2c_get_clientdata(client);
+	u8 fanmode;
+
+	if (val < 0 || val > 4)
+		return -EINVAL;
+
+	fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
+	if (data->kind == f75387) {
+		/* For now, deny dangerous toggling of duty mode */
+		if (duty_mode_enabled(data->pwm_enable[nr]) !=
+				duty_mode_enabled(val))
+			return -EOPNOTSUPP;
+		/* clear each fanX_mode bit before setting them properly */
+		fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr));
+		fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr));
+		switch (val) {
+		case 0: /* full speed */
+			fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
+			fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
+			data->pwm[nr] = 255;
+			break;
+		case 1: /* PWM */
+			fanmode  |= (1 << F75387_FAN_MANU_MODE(nr));
+			fanmode  |= (1 << F75387_FAN_DUTY_MODE(nr));
+			break;
+		case 2: /* Automatic, speed mode */
+			break;
+		case 3: /* fan speed */
+			fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
+			break;
+		case 4: /* Automatic, pwm */
+			fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
+			break;
+		}
+	} else {
+		/* clear each fanX_mode bit before setting them properly */
+		fanmode &= ~(3 << FAN_CTRL_MODE(nr));
+		switch (val) {
+		case 0: /* full speed */
+			fanmode  |= (3 << FAN_CTRL_MODE(nr));
+			data->pwm[nr] = 255;
+			break;
+		case 1: /* PWM */
+			fanmode  |= (3 << FAN_CTRL_MODE(nr));
+			break;
+		case 2: /* AUTOMATIC*/
+			fanmode  |= (1 << FAN_CTRL_MODE(nr));
+			break;
+		case 3: /* fan speed */
+			break;
+		case 4: /* Automatic pwm */
+			return -EINVAL;
+		}
+	}
+
+	f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
+	data->pwm_enable[nr] = val;
+	if (val == 0)
+		f75375_write_pwm(client, nr);
+	return 0;
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	err = set_pwm_enable_direct(client, nr, val);
+	mutex_unlock(&data->update_lock);
+	return err ? err : count;
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+	u8 conf;
+	char reg, ctrl;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (!(val == 0 || val == 1))
+		return -EINVAL;
+
+	/* F75373 does not support DC (linear voltage) fan control mode */
+	if (data->kind == f75373 && val == 0)
+		return -EINVAL;
+
+	/* take care for different registers */
+	if (data->kind == f75387) {
+		reg = F75375_REG_FAN_TIMER;
+		ctrl = F75387_FAN_CTRL_LINEAR(nr);
+	} else {
+		reg = F75375_REG_CONFIG1;
+		ctrl = F75375_FAN_CTRL_LINEAR(nr);
+	}
+
+	mutex_lock(&data->update_lock);
+	conf = f75375_read8(client, reg);
+	conf &= ~(1 << ctrl);
+
+	if (val == 0)
+		conf |= (1 << ctrl);
+
+	f75375_write8(client, reg, conf);
+	data->pwm_mode[nr] = val;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm[nr]);
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_mode[nr]);
+}
+
+#define VOLT_FROM_REG(val) ((val) * 8)
+#define VOLT_TO_REG(val) ((val) / 8)
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = val;
+	f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = val;
+	f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define TEMP_TO_REG(val) ((val) / 1000)
+#define TEMP11_FROM_REG(reg)	((reg) / 32 * 125)
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct f75375_data *data = f75375_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(TEMP_TO_REG(val), 0, 127);
+	mutex_lock(&data->update_lock);
+	data->temp_high[nr] = val;
+	f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(TEMP_TO_REG(val), 0, 127);
+	mutex_lock(&data->update_lock);
+	data->temp_max_hyst[nr] = val;
+	f75375_write8(client, F75375_REG_TEMP_HYST(nr),
+		data->temp_max_hyst[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_fan(thing) \
+static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
+			char *buf)\
+{\
+	int nr = to_sensor_dev_attr(attr)->index;\
+	struct f75375_data *data = f75375_update_device(dev); \
+	return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
+}
+
+show_fan(fan);
+show_fan(fan_min);
+show_fan(fan_max);
+show_fan(fan_target);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
+	show_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
+	show_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR,
+	show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR,
+	show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR,
+	show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR,
+	show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
+	show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
+	show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
+	show_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
+	show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
+	show_temp_max_hyst, set_temp_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
+	show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO, show_fan_max, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
+	show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO|S_IWUSR,
+	show_fan_target, set_fan_target, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IRUGO, show_fan_max, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
+	show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO|S_IWUSR,
+	show_fan_target, set_fan_target, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
+	show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
+	show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO,
+	show_pwm_mode, set_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
+	show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
+	show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO,
+	show_pwm_mode, set_pwm_mode, 1);
+
+static struct attribute *f75375_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_target.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_max.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_target.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group f75375_group = {
+	.attrs = f75375_attributes,
+};
+
+static void f75375_init(struct i2c_client *client, struct f75375_data *data,
+		struct f75375s_platform_data *f75375s_pdata)
+{
+	int nr;
+
+	if (!f75375s_pdata) {
+		u8 conf, mode;
+		int nr;
+
+		conf = f75375_read8(client, F75375_REG_CONFIG1);
+		mode = f75375_read8(client, F75375_REG_FAN_TIMER);
+		for (nr = 0; nr < 2; nr++) {
+			if (data->kind == f75387) {
+				bool manu, duty;
+
+				if (!(mode & (1 << F75387_FAN_CTRL_LINEAR(nr))))
+					data->pwm_mode[nr] = 1;
+
+				manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1);
+				duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1);
+				if (!manu && duty)
+					/* auto, pwm */
+					data->pwm_enable[nr] = 4;
+				else if (manu && !duty)
+					/* manual, speed */
+					data->pwm_enable[nr] = 3;
+				else if (!manu && !duty)
+					/* automatic, speed */
+					data->pwm_enable[nr] = 2;
+				else
+					/* manual, pwm */
+					data->pwm_enable[nr] = 1;
+			} else {
+				if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr))))
+					data->pwm_mode[nr] = 1;
+
+				switch ((mode >> FAN_CTRL_MODE(nr)) & 3) {
+				case 0:		/* speed */
+					data->pwm_enable[nr] = 3;
+					break;
+				case 1:		/* automatic */
+					data->pwm_enable[nr] = 2;
+					break;
+				default:	/* manual */
+					data->pwm_enable[nr] = 1;
+					break;
+				}
+			}
+		}
+		return;
+	}
+
+	set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);
+	set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);
+	for (nr = 0; nr < 2; nr++) {
+		if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
+		    !duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
+			continue;
+		data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255);
+		f75375_write_pwm(client, nr);
+	}
+
+}
+
+static int f75375_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct f75375_data *data;
+	struct f75375s_platform_data *f75375s_pdata =
+			dev_get_platdata(&client->dev);
+	int err;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+	data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+	data->kind = id->driver_data;
+
+	err = sysfs_create_group(&client->dev.kobj, &f75375_group);
+	if (err)
+		return err;
+
+	if (data->kind != f75373) {
+		err = sysfs_chmod_file(&client->dev.kobj,
+			&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+			S_IRUGO | S_IWUSR);
+		if (err)
+			goto exit_remove;
+		err = sysfs_chmod_file(&client->dev.kobj,
+			&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+			S_IRUGO | S_IWUSR);
+		if (err)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	f75375_init(client, data, f75375s_pdata);
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &f75375_group);
+	return err;
+}
+
+static int f75375_remove(struct i2c_client *client)
+{
+	struct f75375_data *data = i2c_get_clientdata(client);
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &f75375_group);
+	return 0;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int f75375_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u16 vendid, chipid;
+	u8 version;
+	const char *name;
+
+	vendid = f75375_read16(client, F75375_REG_VENDOR);
+	chipid = f75375_read16(client, F75375_CHIP_ID);
+	if (vendid != 0x1934)
+		return -ENODEV;
+
+	if (chipid == 0x0306)
+		name = "f75375";
+	else if (chipid == 0x0204)
+		name = "f75373";
+	else if (chipid == 0x0410)
+		name = "f75387";
+	else
+		return -ENODEV;
+
+	version = f75375_read8(client, F75375_REG_VERSION);
+	dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+module_i2c_driver(f75375_driver);
+
+MODULE_AUTHOR("Riku Voipio");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver");
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
new file mode 100644
index 0000000..5f7067d
--- /dev/null
+++ b/drivers/hwmon/fam15h_power.c
@@ -0,0 +1,312 @@
+/*
+ * fam15h_power.c - AMD Family 15h processor power monitoring
+ *
+ * Copyright (c) 2011 Advanced Micro Devices, Inc.
+ * Author: Andreas Herrmann <herrmann.der.user@googlemail.com>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+
+MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
+MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
+MODULE_LICENSE("GPL");
+
+/* D18F3 */
+#define REG_NORTHBRIDGE_CAP		0xe8
+
+/* D18F4 */
+#define REG_PROCESSOR_TDP		0x1b8
+
+/* D18F5 */
+#define REG_TDP_RUNNING_AVERAGE		0xe0
+#define REG_TDP_LIMIT3			0xe8
+
+#define FAM15H_MIN_NUM_ATTRS		2
+#define FAM15H_NUM_GROUPS		2
+
+#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR	0xc001007b
+
+struct fam15h_power_data {
+	struct pci_dev *pdev;
+	unsigned int tdp_to_watts;
+	unsigned int base_tdp;
+	unsigned int processor_pwr_watts;
+	unsigned int cpu_pwr_sample_ratio;
+	const struct attribute_group *groups[FAM15H_NUM_GROUPS];
+	struct attribute_group group;
+	/* maximum accumulated power of a compute unit */
+	u64 max_cu_acc_power;
+};
+
+static ssize_t show_power(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	u32 val, tdp_limit, running_avg_range;
+	s32 running_avg_capture;
+	u64 curr_pwr_watts;
+	struct fam15h_power_data *data = dev_get_drvdata(dev);
+	struct pci_dev *f4 = data->pdev;
+
+	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+				  REG_TDP_RUNNING_AVERAGE, &val);
+
+	/*
+	 * On Carrizo and later platforms, TdpRunAvgAccCap bit field
+	 * is extended to 4:31 from 4:25.
+	 */
+	if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60) {
+		running_avg_capture = val >> 4;
+		running_avg_capture = sign_extend32(running_avg_capture, 27);
+	} else {
+		running_avg_capture = (val >> 4) & 0x3fffff;
+		running_avg_capture = sign_extend32(running_avg_capture, 21);
+	}
+
+	running_avg_range = (val & 0xf) + 1;
+
+	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+				  REG_TDP_LIMIT3, &val);
+
+	tdp_limit = val >> 16;
+	curr_pwr_watts = ((u64)(tdp_limit +
+				data->base_tdp)) << running_avg_range;
+	curr_pwr_watts -= running_avg_capture;
+	curr_pwr_watts *= data->tdp_to_watts;
+
+	/*
+	 * Convert to microWatt
+	 *
+	 * power is in Watt provided as fixed point integer with
+	 * scaling factor 1/(2^16).  For conversion we use
+	 * (10^6)/(2^16) = 15625/(2^10)
+	 */
+	curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range);
+	return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
+}
+static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
+
+static ssize_t show_power_crit(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->processor_pwr_watts);
+}
+static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
+
+static int fam15h_power_init_attrs(struct pci_dev *pdev,
+				   struct fam15h_power_data *data)
+{
+	int n = FAM15H_MIN_NUM_ATTRS;
+	struct attribute **fam15h_power_attrs;
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	if (c->x86 == 0x15 &&
+	    (c->x86_model <= 0xf ||
+	     (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+		n += 1;
+
+	fam15h_power_attrs = devm_kcalloc(&pdev->dev, n,
+					  sizeof(*fam15h_power_attrs),
+					  GFP_KERNEL);
+
+	if (!fam15h_power_attrs)
+		return -ENOMEM;
+
+	n = 0;
+	fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr;
+	if (c->x86 == 0x15 &&
+	    (c->x86_model <= 0xf ||
+	     (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+		fam15h_power_attrs[n++] = &dev_attr_power1_input.attr;
+
+	data->group.attrs = fam15h_power_attrs;
+
+	return 0;
+}
+
+static bool should_load_on_this_node(struct pci_dev *f4)
+{
+	u32 val;
+
+	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3),
+				  REG_NORTHBRIDGE_CAP, &val);
+	if ((val & BIT(29)) && ((val >> 30) & 3))
+		return false;
+
+	return true;
+}
+
+/*
+ * Newer BKDG versions have an updated recommendation on how to properly
+ * initialize the running average range (was: 0xE, now: 0x9). This avoids
+ * counter saturations resulting in bogus power readings.
+ * We correct this value ourselves to cope with older BIOSes.
+ */
+static const struct pci_device_id affected_device[] = {
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+	{ 0 }
+};
+
+static void tweak_runavg_range(struct pci_dev *pdev)
+{
+	u32 val;
+
+	/*
+	 * let this quirk apply only to the current version of the
+	 * northbridge, since future versions may change the behavior
+	 */
+	if (!pci_match_id(affected_device, pdev))
+		return;
+
+	pci_bus_read_config_dword(pdev->bus,
+		PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
+		REG_TDP_RUNNING_AVERAGE, &val);
+	if ((val & 0xf) != 0xe)
+		return;
+
+	val &= ~0xf;
+	val |=  0x9;
+	pci_bus_write_config_dword(pdev->bus,
+		PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
+		REG_TDP_RUNNING_AVERAGE, val);
+}
+
+#ifdef CONFIG_PM
+static int fam15h_power_resume(struct pci_dev *pdev)
+{
+	tweak_runavg_range(pdev);
+	return 0;
+}
+#else
+#define fam15h_power_resume NULL
+#endif
+
+static int fam15h_power_init_data(struct pci_dev *f4,
+				  struct fam15h_power_data *data)
+{
+	u32 val, eax, ebx, ecx, edx;
+	u64 tmp;
+	int ret;
+
+	pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
+	data->base_tdp = val >> 16;
+	tmp = val & 0xffff;
+
+	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+				  REG_TDP_LIMIT3, &val);
+
+	data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f);
+	tmp *= data->tdp_to_watts;
+
+	/* result not allowed to be >= 256W */
+	if ((tmp >> 16) >= 256)
+		dev_warn(&f4->dev,
+			 "Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)\n",
+			 (unsigned int) (tmp >> 16));
+
+	/* convert to microWatt */
+	data->processor_pwr_watts = (tmp * 15625) >> 10;
+
+	ret = fam15h_power_init_attrs(f4, data);
+	if (ret)
+		return ret;
+
+	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
+
+	/* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */
+	if (!(edx & BIT(12)))
+		return 0;
+
+	/*
+	 * determine the ratio of the compute unit power accumulator
+	 * sample period to the PTSC counter period by executing CPUID
+	 * Fn8000_0007:ECX
+	 */
+	data->cpu_pwr_sample_ratio = ecx;
+
+	if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
+		pr_err("Failed to read max compute unit power accumulator MSR\n");
+		return -ENODEV;
+	}
+
+	data->max_cu_acc_power = tmp;
+
+	return 0;
+}
+
+static int fam15h_power_probe(struct pci_dev *pdev,
+			      const struct pci_device_id *id)
+{
+	struct fam15h_power_data *data;
+	struct device *dev = &pdev->dev;
+	struct device *hwmon_dev;
+	int ret;
+
+	/*
+	 * though we ignore every other northbridge, we still have to
+	 * do the tweaking on _each_ node in MCM processors as the counters
+	 * are working hand-in-hand
+	 */
+	tweak_runavg_range(pdev);
+
+	if (!should_load_on_this_node(pdev))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ret = fam15h_power_init_data(pdev, data);
+	if (ret)
+		return ret;
+
+	data->pdev = pdev;
+
+	data->groups[0] = &data->group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power",
+							   data,
+							   &data->groups[0]);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct pci_device_id fam15h_power_id_table[] = {
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
+	{}
+};
+MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
+
+static struct pci_driver fam15h_power_driver = {
+	.name = "fam15h_power",
+	.id_table = fam15h_power_id_table,
+	.probe = fam15h_power_probe,
+	.resume = fam15h_power_resume,
+};
+
+module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
new file mode 100644
index 0000000..d58abdc
--- /dev/null
+++ b/drivers/hwmon/fschmd.c
@@ -0,0 +1,1389 @@
+/*
+ * fschmd.c
+ *
+ * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * 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.
+ */
+
+/*
+ *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
+ *  Scylla, Heracles, Heimdall, Hades and Syleus chips
+ *
+ *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
+ *  (candidate) fschmd drivers:
+ *  Copyright (C) 2006 Thilo Cestonaro
+ *			<thilo.cestonaro.external@fujitsu-siemens.com>
+ *  Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
+ *  Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
+ *  Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
+ *  Copyright (C) 2000 Hermann Jung <hej@odn.de>
+ */
+
+#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>
+#include <linux/dmi.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+
+/* Insmod parameters */
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
+
+/*
+ * The FSCHMD registers and other defines
+ */
+
+/* chip identification */
+#define FSCHMD_REG_IDENT_0		0x00
+#define FSCHMD_REG_IDENT_1		0x01
+#define FSCHMD_REG_IDENT_2		0x02
+#define FSCHMD_REG_REVISION		0x03
+
+/* global control and status */
+#define FSCHMD_REG_EVENT_STATE		0x04
+#define FSCHMD_REG_CONTROL		0x05
+
+#define FSCHMD_CONTROL_ALERT_LED	0x01
+
+/* watchdog */
+static const u8 FSCHMD_REG_WDOG_CONTROL[7] = {
+	0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
+static const u8 FSCHMD_REG_WDOG_STATE[7] = {
+	0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
+static const u8 FSCHMD_REG_WDOG_PRESET[7] = {
+	0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
+
+#define FSCHMD_WDOG_CONTROL_TRIGGER	0x10
+#define FSCHMD_WDOG_CONTROL_STARTED	0x10 /* the same as trigger */
+#define FSCHMD_WDOG_CONTROL_STOP	0x20
+#define FSCHMD_WDOG_CONTROL_RESOLUTION	0x40
+
+#define FSCHMD_WDOG_STATE_CARDRESET	0x02
+
+/* voltages, weird order is to keep the same order as the old drivers */
+static const u8 FSCHMD_REG_VOLT[7][6] = {
+	{ 0x45, 0x42, 0x48 },				/* pos */
+	{ 0x45, 0x42, 0x48 },				/* her */
+	{ 0x45, 0x42, 0x48 },				/* scy */
+	{ 0x45, 0x42, 0x48 },				/* hrc */
+	{ 0x45, 0x42, 0x48 },				/* hmd */
+	{ 0x21, 0x20, 0x22 },				/* hds */
+	{ 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 },		/* syl */
+};
+
+static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
+
+/*
+ * minimum pwm at which the fan is driven (pwm can by increased depending on
+ * the temp. Notice that for the scy some fans share there minimum speed.
+ * Also notice that with the scy the sensor order is different than with the
+ * other chips, this order was in the 2.4 driver and kept for consistency.
+ */
+static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
+	{ 0x55, 0x65 },					/* pos */
+	{ 0x55, 0x65, 0xb5 },				/* her */
+	{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },		/* scy */
+	{ 0x55, 0x65, 0xa5, 0xb5 },			/* hrc */
+	{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 },		/* hmd */
+	{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 },		/* hds */
+	{ 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 },	/* syl */
+};
+
+/* actual fan speed */
+static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
+	{ 0x0e, 0x6b, 0xab },				/* pos */
+	{ 0x0e, 0x6b, 0xbb },				/* her */
+	{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },		/* scy */
+	{ 0x0e, 0x6b, 0xab, 0xbb },			/* hrc */
+	{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb },		/* hmd */
+	{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb },		/* hds */
+	{ 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 },	/* syl */
+};
+
+/* fan status registers */
+static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
+	{ 0x0d, 0x62, 0xa2 },				/* pos */
+	{ 0x0d, 0x62, 0xb2 },				/* her */
+	{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },		/* scy */
+	{ 0x0d, 0x62, 0xa2, 0xb2 },			/* hrc */
+	{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 },		/* hmd */
+	{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 },		/* hds */
+	{ 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 },	/* syl */
+};
+
+/* fan ripple / divider registers */
+static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
+	{ 0x0f, 0x6f, 0xaf },				/* pos */
+	{ 0x0f, 0x6f, 0xbf },				/* her */
+	{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },		/* scy */
+	{ 0x0f, 0x6f, 0xaf, 0xbf },			/* hrc */
+	{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },		/* hmd */
+	{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },		/* hds */
+	{ 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 },	/* syl */
+};
+
+static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
+
+/* Fan status register bitmasks */
+#define FSCHMD_FAN_ALARM	0x04 /* called fault by FSC! */
+#define FSCHMD_FAN_NOT_PRESENT	0x08
+#define FSCHMD_FAN_DISABLED	0x80
+
+
+/* actual temperature registers */
+static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
+	{ 0x64, 0x32, 0x35 },				/* pos */
+	{ 0x64, 0x32, 0x35 },				/* her */
+	{ 0x64, 0xD0, 0x32, 0x35 },			/* scy */
+	{ 0x64, 0x32, 0x35 },				/* hrc */
+	{ 0x70, 0x80, 0x90, 0xd0, 0xe0 },		/* hmd */
+	{ 0x70, 0x80, 0x90, 0xd0, 0xe0 },		/* hds */
+	{ 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8,		/* syl */
+	  0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
+};
+
+/* temperature state registers */
+static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
+	{ 0x71, 0x81, 0x91 },				/* pos */
+	{ 0x71, 0x81, 0x91 },				/* her */
+	{ 0x71, 0xd1, 0x81, 0x91 },			/* scy */
+	{ 0x71, 0x81, 0x91 },				/* hrc */
+	{ 0x71, 0x81, 0x91, 0xd1, 0xe1 },		/* hmd */
+	{ 0x71, 0x81, 0x91, 0xd1, 0xe1 },		/* hds */
+	{ 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9,		/* syl */
+	  0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
+};
+
+/*
+ * temperature high limit registers, FSC does not document these. Proven to be
+ * there with field testing on the fscher and fschrc, already supported / used
+ * in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
+ * at these addresses, but doesn't want to confirm they are the same as with
+ * the fscher??
+ */
+static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
+	{ 0, 0, 0 },					/* pos */
+	{ 0x76, 0x86, 0x96 },				/* her */
+	{ 0x76, 0xd6, 0x86, 0x96 },			/* scy */
+	{ 0x76, 0x86, 0x96 },				/* hrc */
+	{ 0x76, 0x86, 0x96, 0xd6, 0xe6 },		/* hmd */
+	{ 0x76, 0x86, 0x96, 0xd6, 0xe6 },		/* hds */
+	{ 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa,		/* syl */
+	  0xba, 0xca, 0xda, 0xea, 0xfa },
+};
+
+/*
+ * These were found through experimenting with an fscher, currently they are
+ * not used, but we keep them around for future reference.
+ * On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
+ * AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
+ * the fan speed.
+ * static const u8 FSCHER_REG_TEMP_AUTOP1[] =	{ 0x73, 0x83, 0x93 };
+ * static const u8 FSCHER_REG_TEMP_AUTOP2[] =	{ 0x75, 0x85, 0x95 };
+ */
+
+static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
+
+/* temp status register bitmasks */
+#define FSCHMD_TEMP_WORKING	0x01
+#define FSCHMD_TEMP_ALERT	0x02
+#define FSCHMD_TEMP_DISABLED	0x80
+/* there only really is an alarm if the sensor is working and alert == 1 */
+#define FSCHMD_TEMP_ALARM_MASK \
+	(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
+
+/*
+ * Functions declarations
+ */
+
+static int fschmd_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
+static int fschmd_detect(struct i2c_client *client,
+			 struct i2c_board_info *info);
+static int fschmd_remove(struct i2c_client *client);
+static struct fschmd_data *fschmd_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id fschmd_id[] = {
+	{ "fscpos", fscpos },
+	{ "fscher", fscher },
+	{ "fscscy", fscscy },
+	{ "fschrc", fschrc },
+	{ "fschmd", fschmd },
+	{ "fschds", fschds },
+	{ "fscsyl", fscsyl },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, fschmd_id);
+
+static struct i2c_driver fschmd_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "fschmd",
+	},
+	.probe		= fschmd_probe,
+	.remove		= fschmd_remove,
+	.id_table	= fschmd_id,
+	.detect		= fschmd_detect,
+	.address_list	= normal_i2c,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct fschmd_data {
+	struct i2c_client *client;
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	struct mutex watchdog_lock;
+	struct list_head list; /* member of the watchdog_data_list */
+	struct kref kref;
+	struct miscdevice watchdog_miscdev;
+	enum chips kind;
+	unsigned long watchdog_is_open;
+	char watchdog_expect_close;
+	char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	u8 revision;            /* chip revision */
+	u8 global_control;	/* global control register */
+	u8 watchdog_control;    /* watchdog control register */
+	u8 watchdog_state;      /* watchdog status register */
+	u8 watchdog_preset;     /* watchdog counter preset on trigger val */
+	u8 volt[6];		/* voltage */
+	u8 temp_act[11];	/* temperature */
+	u8 temp_status[11];	/* status of sensor */
+	u8 temp_max[11];	/* high temp limit, notice: undocumented! */
+	u8 fan_act[7];		/* fans revolutions per second */
+	u8 fan_status[7];	/* fan status */
+	u8 fan_min[7];		/* fan min value for rps */
+	u8 fan_ripple[7];	/* divider for rps */
+};
+
+/*
+ * Global variables to hold information read from special DMI tables, which are
+ * available on FSC machines with an fscher or later chip. There is no need to
+ * protect these with a lock as they are only modified from our attach function
+ * which always gets called with the i2c-core lock held and never accessed
+ * before the attach function is done with them.
+ */
+static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
+static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
+static int dmi_vref = -1;
+
+/*
+ * Somewhat ugly :( global data pointer list with all fschmd devices, so that
+ * we can find our device data as when using misc_register there is no other
+ * method to get to ones device data from the open fop.
+ */
+static LIST_HEAD(watchdog_data_list);
+/* Note this lock not only protect list access, but also data.kref access */
+static DEFINE_MUTEX(watchdog_data_mutex);
+
+/*
+ * Release our data struct when we're detached from the i2c client *and* all
+ * references to our watchdog device are released
+ */
+static void fschmd_release_resources(struct kref *ref)
+{
+	struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
+	kfree(data);
+}
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static ssize_t show_in_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	const int max_reading[3] = { 14200, 6600, 3300 };
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	if (data->kind == fscher || data->kind >= fschrc)
+		return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
+			dmi_mult[index]) / 255 + dmi_offset[index]);
+	else
+		return sprintf(buf, "%d\n", (data->volt[index] *
+			max_reading[index] + 128) / 255);
+}
+
+
+#define TEMP_FROM_REG(val)	(((val) - 128) * 1000)
+
+static ssize_t show_temp_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = dev_get_drvdata(dev);
+	long v;
+	int err;
+
+	err = kstrtol(buf, 10, &v);
+	if (err)
+		return err;
+
+	v = clamp_val(v / 1000, -128, 127) + 128;
+
+	mutex_lock(&data->update_lock);
+	i2c_smbus_write_byte_data(to_i2c_client(dev),
+		FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
+	data->temp_max[index] = v;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	/* bit 0 set means sensor working ok, so no fault! */
+	if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
+		return sprintf(buf, "0\n");
+	else
+		return sprintf(buf, "1\n");
+}
+
+static ssize_t show_temp_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
+			FSCHMD_TEMP_ALARM_MASK)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+
+#define RPM_FROM_REG(val)	((val) * 60)
+
+static ssize_t show_fan_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	/* bits 2..7 reserved => mask with 3 */
+	return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
+}
+
+static ssize_t store_fan_div(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	u8 reg;
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = dev_get_drvdata(dev);
+	/* supported values: 2, 4, 8 */
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	switch (v) {
+	case 2:
+		v = 1;
+		break;
+	case 4:
+		v = 2;
+		break;
+	case 8:
+		v = 3;
+		break;
+	default:
+		dev_err(dev,
+			"fan_div value %lu not supported. Choose one of 2, 4 or 8!\n",
+			v);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+
+	reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
+		FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
+
+	/* bits 2..7 reserved => mask with 0x03 */
+	reg &= ~0x03;
+	reg |= v;
+
+	i2c_smbus_write_byte_data(to_i2c_client(dev),
+		FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
+
+	data->fan_ripple[index] = reg;
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	if (data->fan_status[index] & FSCHMD_FAN_ALARM)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_fan_fault(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+
+static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = fschmd_update_device(dev);
+	int val = data->fan_min[index];
+
+	/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+	if (val || data->kind == fscsyl)
+		val = val / 2 + 128;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct fschmd_data *data = dev_get_drvdata(dev);
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+	if (v || data->kind == fscsyl) {
+		v = clamp_val(v, 128, 255);
+		v = (v - 128) * 2 + 1;
+	}
+
+	mutex_lock(&data->update_lock);
+
+	i2c_smbus_write_byte_data(to_i2c_client(dev),
+		FSCHMD_REG_FAN_MIN[data->kind][index], v);
+	data->fan_min[index] = v;
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+/*
+ * The FSC hwmon family has the ability to force an attached alert led to flash
+ * from software, we export this as an alert_led sysfs attr
+ */
+static ssize_t show_alert_led(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct fschmd_data *data = fschmd_update_device(dev);
+
+	if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_alert_led(struct device *dev,
+	struct device_attribute *devattr, const char *buf, size_t count)
+{
+	u8 reg;
+	struct fschmd_data *data = dev_get_drvdata(dev);
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
+
+	if (v)
+		reg |= FSCHMD_CONTROL_ALERT_LED;
+	else
+		reg &= ~FSCHMD_CONTROL_ALERT_LED;
+
+	i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
+
+	data->global_control = reg;
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
+
+static struct sensor_device_attribute fschmd_attr[] = {
+	SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
+	SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
+	SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
+	SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
+	SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
+	SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
+};
+
+static struct sensor_device_attribute fschmd_temp_attr[] = {
+	SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+	SENSOR_ATTR(temp1_max,   0644, show_temp_max, store_temp_max, 0),
+	SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
+	SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
+	SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+	SENSOR_ATTR(temp2_max,   0644, show_temp_max, store_temp_max, 1),
+	SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
+	SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
+	SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
+	SENSOR_ATTR(temp3_max,   0644, show_temp_max, store_temp_max, 2),
+	SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
+	SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
+	SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
+	SENSOR_ATTR(temp4_max,   0644, show_temp_max, store_temp_max, 3),
+	SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
+	SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
+	SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
+	SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),
+	SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
+	SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+	SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
+	SENSOR_ATTR(temp6_max,   0644, show_temp_max, store_temp_max, 5),
+	SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
+	SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
+	SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
+	SENSOR_ATTR(temp7_max,   0644, show_temp_max, store_temp_max, 6),
+	SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
+	SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
+	SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
+	SENSOR_ATTR(temp8_max,   0644, show_temp_max, store_temp_max, 7),
+	SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
+	SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
+	SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
+	SENSOR_ATTR(temp9_max,   0644, show_temp_max, store_temp_max, 8),
+	SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
+	SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
+	SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
+	SENSOR_ATTR(temp10_max,   0644, show_temp_max, store_temp_max, 9),
+	SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
+	SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
+	SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
+	SENSOR_ATTR(temp11_max,   0644, show_temp_max, store_temp_max, 10),
+	SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
+	SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
+};
+
+static struct sensor_device_attribute fschmd_fan_attr[] = {
+	SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
+	SENSOR_ATTR(fan1_div,   0644, show_fan_div, store_fan_div, 0),
+	SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
+	SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
+	SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 0),
+	SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
+	SENSOR_ATTR(fan2_div,   0644, show_fan_div, store_fan_div, 1),
+	SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
+	SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
+	SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 1),
+	SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
+	SENSOR_ATTR(fan3_div,   0644, show_fan_div, store_fan_div, 2),
+	SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
+	SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
+	SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 2),
+	SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
+	SENSOR_ATTR(fan4_div,   0644, show_fan_div, store_fan_div, 3),
+	SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
+	SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
+	SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 3),
+	SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
+	SENSOR_ATTR(fan5_div,   0644, show_fan_div, store_fan_div, 4),
+	SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
+	SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
+	SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 4),
+	SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
+	SENSOR_ATTR(fan6_div,   0644, show_fan_div, store_fan_div, 5),
+	SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
+	SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
+	SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 5),
+	SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
+	SENSOR_ATTR(fan7_div,   0644, show_fan_div, store_fan_div, 6),
+	SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
+	SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
+	SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+		store_pwm_auto_point1_pwm, 6),
+};
+
+
+/*
+ * Watchdog routines
+ */
+
+static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
+{
+	int ret, resolution;
+	int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
+
+	/* 2 second or 60 second resolution? */
+	if (timeout <= 510 || kind == fscpos || kind == fscscy)
+		resolution = 2;
+	else
+		resolution = 60;
+
+	if (timeout < resolution || timeout > (resolution * 255))
+		return -EINVAL;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	if (resolution == 2)
+		data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
+	else
+		data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
+
+	data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
+
+	/* Write new timeout value */
+	i2c_smbus_write_byte_data(data->client,
+		FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
+	/* Write new control register, do not trigger! */
+	i2c_smbus_write_byte_data(data->client,
+		FSCHMD_REG_WDOG_CONTROL[data->kind],
+		data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
+
+	ret = data->watchdog_preset * resolution;
+
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_get_timeout(struct fschmd_data *data)
+{
+	int timeout;
+
+	mutex_lock(&data->watchdog_lock);
+	if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
+		timeout = data->watchdog_preset * 60;
+	else
+		timeout = data->watchdog_preset * 2;
+	mutex_unlock(&data->watchdog_lock);
+
+	return timeout;
+}
+
+static int watchdog_trigger(struct fschmd_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
+	i2c_smbus_write_byte_data(data->client,
+				  FSCHMD_REG_WDOG_CONTROL[data->kind],
+				  data->watchdog_control);
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_stop(struct fschmd_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
+	/*
+	 * Don't store the stop flag in our watchdog control register copy, as
+	 * its a write only bit (read always returns 0)
+	 */
+	i2c_smbus_write_byte_data(data->client,
+		FSCHMD_REG_WDOG_CONTROL[data->kind],
+		data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_open(struct inode *inode, struct file *filp)
+{
+	struct fschmd_data *pos, *data = NULL;
+	int watchdog_is_open;
+
+	/*
+	 * We get called from drivers/char/misc.c with misc_mtx hold, and we
+	 * call misc_register() from fschmd_probe() with watchdog_data_mutex
+	 * hold, as misc_register() takes the misc_mtx lock, this is a possible
+	 * deadlock, so we use mutex_trylock here.
+	 */
+	if (!mutex_trylock(&watchdog_data_mutex))
+		return -ERESTARTSYS;
+	list_for_each_entry(pos, &watchdog_data_list, list) {
+		if (pos->watchdog_miscdev.minor == iminor(inode)) {
+			data = pos;
+			break;
+		}
+	}
+	/* Note we can never not have found data, so we don't check for this */
+	watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
+	if (!watchdog_is_open)
+		kref_get(&data->kref);
+	mutex_unlock(&watchdog_data_mutex);
+
+	if (watchdog_is_open)
+		return -EBUSY;
+
+	/* Start the watchdog */
+	watchdog_trigger(data);
+	filp->private_data = data;
+
+	return nonseekable_open(inode, filp);
+}
+
+static int watchdog_release(struct inode *inode, struct file *filp)
+{
+	struct fschmd_data *data = filp->private_data;
+
+	if (data->watchdog_expect_close) {
+		watchdog_stop(data);
+		data->watchdog_expect_close = 0;
+	} else {
+		watchdog_trigger(data);
+		dev_crit(&data->client->dev,
+			"unexpected close, not stopping watchdog!\n");
+	}
+
+	clear_bit(0, &data->watchdog_is_open);
+
+	mutex_lock(&watchdog_data_mutex);
+	kref_put(&data->kref, fschmd_release_resources);
+	mutex_unlock(&watchdog_data_mutex);
+
+	return 0;
+}
+
+static ssize_t watchdog_write(struct file *filp, const char __user *buf,
+	size_t count, loff_t *offset)
+{
+	int ret;
+	struct fschmd_data *data = filp->private_data;
+
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* Clear it in case it was set with a previous write */
+			data->watchdog_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					data->watchdog_expect_close = 1;
+			}
+		}
+		ret = watchdog_trigger(data);
+		if (ret < 0)
+			return ret;
+	}
+	return count;
+}
+
+static long watchdog_ioctl(struct file *filp, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+				WDIOF_CARDRESET,
+		.identity = "FSC watchdog"
+	};
+	int i, ret = 0;
+	struct fschmd_data *data = filp->private_data;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ident.firmware_version = data->revision;
+		if (!nowayout)
+			ident.options |= WDIOF_MAGICCLOSE;
+		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
+			ret = -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int __user *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
+			ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
+		else
+			ret = put_user(0, (int __user *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		ret = watchdog_trigger(data);
+		break;
+
+	case WDIOC_GETTIMEOUT:
+		i = watchdog_get_timeout(data);
+		ret = put_user(i, (int __user *)arg);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(i, (int __user *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = watchdog_set_timeout(data, i);
+		if (ret > 0)
+			ret = put_user(ret, (int __user *)arg);
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(i, (int __user *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (i & WDIOS_DISABLECARD)
+			ret = watchdog_stop(data);
+		else if (i & WDIOS_ENABLECARD)
+			ret = watchdog_trigger(data);
+		else
+			ret = -EINVAL;
+
+		break;
+	default:
+		ret = -ENOTTY;
+	}
+	return ret;
+}
+
+static const struct file_operations watchdog_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = watchdog_open,
+	.release = watchdog_release,
+	.write = watchdog_write,
+	.unlocked_ioctl = watchdog_ioctl,
+};
+
+
+/*
+ * Detect, register, unregister and update device functions
+ */
+
+/*
+ * DMI decode routine to read voltage scaling factors from special DMI tables,
+ * which are available on FSC machines with an fscher or later chip.
+ */
+static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
+{
+	int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
+
+	/*
+	 * dmi code ugliness, we get passed the address of the contents of
+	 * a complete DMI record, but in the form of a dmi_header pointer, in
+	 * reality this address holds header->length bytes of which the header
+	 * are the first 4 bytes
+	 */
+	u8 *dmi_data = (u8 *)header;
+
+	/* We are looking for OEM-specific type 185 */
+	if (header->type != 185)
+		return;
+
+	/*
+	 * we are looking for what Siemens calls "subtype" 19, the subtype
+	 * is stored in byte 5 of the dmi block
+	 */
+	if (header->length < 5 || dmi_data[4] != 19)
+		return;
+
+	/*
+	 * After the subtype comes 1 unknown byte and then blocks of 5 bytes,
+	 * consisting of what Siemens calls an "Entity" number, followed by
+	 * 2 16-bit words in LSB first order
+	 */
+	for (i = 6; (i + 4) < header->length; i += 5) {
+		/* entity 1 - 3: voltage multiplier and offset */
+		if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
+			/* Our in sensors order and the DMI order differ */
+			const int shuffle[3] = { 1, 0, 2 };
+			int in = shuffle[dmi_data[i] - 1];
+
+			/* Check for twice the same entity */
+			if (found & (1 << in))
+				return;
+
+			mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
+			offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
+
+			found |= 1 << in;
+		}
+
+		/* entity 7: reference voltage */
+		if (dmi_data[i] == 7) {
+			/* Check for twice the same entity */
+			if (found & 0x08)
+				return;
+
+			vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
+
+			found |= 0x08;
+		}
+	}
+
+	if (found == 0x0F) {
+		for (i = 0; i < 3; i++) {
+			dmi_mult[i] = mult[i] * 10;
+			dmi_offset[i] = offset[i] * 10;
+		}
+		/*
+		 * According to the docs there should be separate dmi entries
+		 * for the mult's and offsets of in3-5 of the syl, but on
+		 * my test machine these are not present
+		 */
+		dmi_mult[3] = dmi_mult[2];
+		dmi_mult[4] = dmi_mult[1];
+		dmi_mult[5] = dmi_mult[2];
+		dmi_offset[3] = dmi_offset[2];
+		dmi_offset[4] = dmi_offset[1];
+		dmi_offset[5] = dmi_offset[2];
+		dmi_vref = vref;
+	}
+}
+
+static int fschmd_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	enum chips kind;
+	struct i2c_adapter *adapter = client->adapter;
+	char id[4];
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Detect & Identify the chip */
+	id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
+	id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
+	id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
+	id[3] = '\0';
+
+	if (!strcmp(id, "PEG"))
+		kind = fscpos;
+	else if (!strcmp(id, "HER"))
+		kind = fscher;
+	else if (!strcmp(id, "SCY"))
+		kind = fscscy;
+	else if (!strcmp(id, "HRC"))
+		kind = fschrc;
+	else if (!strcmp(id, "HMD"))
+		kind = fschmd;
+	else if (!strcmp(id, "HDS"))
+		kind = fschds;
+	else if (!strcmp(id, "SYL"))
+		kind = fscsyl;
+	else
+		return -ENODEV;
+
+	strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int fschmd_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct fschmd_data *data;
+	const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
+				"Heracles", "Heimdall", "Hades", "Syleus" };
+	const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
+	int i, err;
+	enum chips kind = id->driver_data;
+
+	data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+	mutex_init(&data->watchdog_lock);
+	INIT_LIST_HEAD(&data->list);
+	kref_init(&data->kref);
+	/*
+	 * Store client pointer in our data struct for watchdog usage
+	 * (where the client is found through a data ptr instead of the
+	 * otherway around)
+	 */
+	data->client = client;
+	data->kind = kind;
+
+	if (kind == fscpos) {
+		/*
+		 * The Poseidon has hardwired temp limits, fill these
+		 * in for the alarm resetting code
+		 */
+		data->temp_max[0] = 70 + 128;
+		data->temp_max[1] = 50 + 128;
+		data->temp_max[2] = 50 + 128;
+	}
+
+	/* Read the special DMI table for fscher and newer chips */
+	if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
+		dmi_walk(fschmd_dmi_decode, NULL);
+		if (dmi_vref == -1) {
+			dev_warn(&client->dev,
+				"Couldn't get voltage scaling factors from "
+				"BIOS DMI table, using builtin defaults\n");
+			dmi_vref = 33;
+		}
+	}
+
+	/* Read in some never changing registers */
+	data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
+	data->global_control = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_CONTROL);
+	data->watchdog_control = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_WDOG_CONTROL[data->kind]);
+	data->watchdog_state = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_WDOG_STATE[data->kind]);
+	data->watchdog_preset = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_WDOG_PRESET[data->kind]);
+
+	err = device_create_file(&client->dev, &dev_attr_alert_led);
+	if (err)
+		goto exit_detach;
+
+	for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
+		err = device_create_file(&client->dev,
+					&fschmd_attr[i].dev_attr);
+		if (err)
+			goto exit_detach;
+	}
+
+	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
+		/* Poseidon doesn't have TEMP_LIMIT registers */
+		if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
+				show_temp_max)
+			continue;
+
+		if (kind == fscsyl) {
+			if (i % 4 == 0)
+				data->temp_status[i / 4] =
+					i2c_smbus_read_byte_data(client,
+						FSCHMD_REG_TEMP_STATE
+						[data->kind][i / 4]);
+			if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
+				continue;
+		}
+
+		err = device_create_file(&client->dev,
+					&fschmd_temp_attr[i].dev_attr);
+		if (err)
+			goto exit_detach;
+	}
+
+	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
+		/* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
+		if (kind == fscpos &&
+				!strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
+					"pwm3_auto_point1_pwm"))
+			continue;
+
+		if (kind == fscsyl) {
+			if (i % 5 == 0)
+				data->fan_status[i / 5] =
+					i2c_smbus_read_byte_data(client,
+						FSCHMD_REG_FAN_STATE
+						[data->kind][i / 5]);
+			if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
+				continue;
+		}
+
+		err = device_create_file(&client->dev,
+					&fschmd_fan_attr[i].dev_attr);
+		if (err)
+			goto exit_detach;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		data->hwmon_dev = NULL;
+		goto exit_detach;
+	}
+
+	/*
+	 * We take the data_mutex lock early so that watchdog_open() cannot
+	 * run when misc_register() has completed, but we've not yet added
+	 * our data to the watchdog_data_list (and set the default timeout)
+	 */
+	mutex_lock(&watchdog_data_mutex);
+	for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
+		/* Register our watchdog part */
+		snprintf(data->watchdog_name, sizeof(data->watchdog_name),
+			"watchdog%c", (i == 0) ? '\0' : ('0' + i));
+		data->watchdog_miscdev.name = data->watchdog_name;
+		data->watchdog_miscdev.fops = &watchdog_fops;
+		data->watchdog_miscdev.minor = watchdog_minors[i];
+		err = misc_register(&data->watchdog_miscdev);
+		if (err == -EBUSY)
+			continue;
+		if (err) {
+			data->watchdog_miscdev.minor = 0;
+			dev_err(&client->dev,
+				"Registering watchdog chardev: %d\n", err);
+			break;
+		}
+
+		list_add(&data->list, &watchdog_data_list);
+		watchdog_set_timeout(data, 60);
+		dev_info(&client->dev,
+			"Registered watchdog chardev major 10, minor: %d\n",
+			watchdog_minors[i]);
+		break;
+	}
+	if (i == ARRAY_SIZE(watchdog_minors)) {
+		data->watchdog_miscdev.minor = 0;
+		dev_warn(&client->dev,
+			 "Couldn't register watchdog chardev (due to no free minor)\n");
+	}
+	mutex_unlock(&watchdog_data_mutex);
+
+	dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
+		names[data->kind], (int) data->revision);
+
+	return 0;
+
+exit_detach:
+	fschmd_remove(client); /* will also free data for us */
+	return err;
+}
+
+static int fschmd_remove(struct i2c_client *client)
+{
+	struct fschmd_data *data = i2c_get_clientdata(client);
+	int i;
+
+	/* Unregister the watchdog (if registered) */
+	if (data->watchdog_miscdev.minor) {
+		misc_deregister(&data->watchdog_miscdev);
+		if (data->watchdog_is_open) {
+			dev_warn(&client->dev,
+				"i2c client detached with watchdog open! "
+				"Stopping watchdog.\n");
+			watchdog_stop(data);
+		}
+		mutex_lock(&watchdog_data_mutex);
+		list_del(&data->list);
+		mutex_unlock(&watchdog_data_mutex);
+		/* Tell the watchdog code the client is gone */
+		mutex_lock(&data->watchdog_lock);
+		data->client = NULL;
+		mutex_unlock(&data->watchdog_lock);
+	}
+
+	/*
+	 * Check if registered in case we're called from fschmd_detect
+	 * to cleanup after an error
+	 */
+	if (data->hwmon_dev)
+		hwmon_device_unregister(data->hwmon_dev);
+
+	device_remove_file(&client->dev, &dev_attr_alert_led);
+	for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
+		device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
+	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
+		device_remove_file(&client->dev,
+					&fschmd_temp_attr[i].dev_attr);
+	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
+		device_remove_file(&client->dev,
+					&fschmd_fan_attr[i].dev_attr);
+
+	mutex_lock(&watchdog_data_mutex);
+	kref_put(&data->kref, fschmd_release_resources);
+	mutex_unlock(&watchdog_data_mutex);
+
+	return 0;
+}
+
+static struct fschmd_data *fschmd_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct fschmd_data *data = i2c_get_clientdata(client);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+
+		for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
+			data->temp_act[i] = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_TEMP_ACT[data->kind][i]);
+			data->temp_status[i] = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_TEMP_STATE[data->kind][i]);
+
+			/* The fscpos doesn't have TEMP_LIMIT registers */
+			if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
+				data->temp_max[i] = i2c_smbus_read_byte_data(
+					client,
+					FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
+
+			/*
+			 * reset alarm if the alarm condition is gone,
+			 * the chip doesn't do this itself
+			 */
+			if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
+					FSCHMD_TEMP_ALARM_MASK &&
+					data->temp_act[i] < data->temp_max[i])
+				i2c_smbus_write_byte_data(client,
+					FSCHMD_REG_TEMP_STATE[data->kind][i],
+					data->temp_status[i]);
+		}
+
+		for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
+			data->fan_act[i] = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_FAN_ACT[data->kind][i]);
+			data->fan_status[i] = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_FAN_STATE[data->kind][i]);
+			data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
+					FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
+
+			/* The fscpos third fan doesn't have a fan_min */
+			if (FSCHMD_REG_FAN_MIN[data->kind][i])
+				data->fan_min[i] = i2c_smbus_read_byte_data(
+					client,
+					FSCHMD_REG_FAN_MIN[data->kind][i]);
+
+			/* reset fan status if speed is back to > 0 */
+			if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
+					data->fan_act[i])
+				i2c_smbus_write_byte_data(client,
+					FSCHMD_REG_FAN_STATE[data->kind][i],
+					data->fan_status[i]);
+		}
+
+		for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
+			data->volt[i] = i2c_smbus_read_byte_data(client,
+					       FSCHMD_REG_VOLT[data->kind][i]);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+module_i2c_driver(fschmd_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
+			"and Syleus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
new file mode 100644
index 0000000..ec6a77d
--- /dev/null
+++ b/drivers/hwmon/g760a.c
@@ -0,0 +1,222 @@
+/*
+ * g760a - Driver for the Global Mixed-mode Technology Inc. G760A
+ *	   fan speed PWM controller chip
+ *
+ * Copyright (C) 2007  Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * Complete datasheet is available at GMT's website:
+ * http://www.gmt.com.tw/product/datasheet/EDS-760A.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.
+ */
+
+#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>
+
+enum g760a_regs {
+	G760A_REG_SET_CNT = 0x00,
+	G760A_REG_ACT_CNT = 0x01,
+	G760A_REG_FAN_STA = 0x02
+};
+
+#define G760A_REG_FAN_STA_RPM_OFF 0x1 /* +/-20% off */
+#define G760A_REG_FAN_STA_RPM_LOW 0x2 /* below 1920rpm */
+
+/* register data is read (and cached) at most once per second */
+#define G760A_UPDATE_INTERVAL (HZ)
+
+struct g760a_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+
+	/* board specific parameters */
+	u32 clk; /* default 32kHz */
+	u16 fan_div; /* default P=2 */
+
+	/* g760a register cache */
+	unsigned int valid:1;
+	unsigned long last_updated; /* In jiffies */
+
+	u8 set_cnt; /* PWM (period) count number; 0xff stops fan */
+	u8 act_cnt; /*   formula: cnt = (CLK * 30)/(rpm * P) */
+	u8 fan_sta; /* bit 0: set when actual fan speed more than 20%
+		     *   outside requested fan speed
+		     * bit 1: set when fan speed below 1920 rpm
+		     */
+};
+
+#define G760A_DEFAULT_CLK 32768
+#define G760A_DEFAULT_FAN_DIV 2
+
+#define PWM_FROM_CNT(cnt)	(0xff-(cnt))
+#define PWM_TO_CNT(pwm)		(0xff-(pwm))
+
+static inline unsigned int rpm_from_cnt(u8 val, u32 clk, u16 div)
+{
+	return ((val == 0x00) ? 0 : ((clk*30)/(val*div)));
+}
+
+/* read/write wrappers */
+static int g760a_read_value(struct i2c_client *client, enum g760a_regs reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int g760a_write_value(struct i2c_client *client, enum g760a_regs reg,
+			     u16 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/*
+ * sysfs attributes
+ */
+
+static struct g760a_data *g760a_update_client(struct device *dev)
+{
+	struct g760a_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + G760A_UPDATE_INTERVAL)
+	    || !data->valid) {
+		dev_dbg(&client->dev, "Starting g760a update\n");
+
+		data->set_cnt = g760a_read_value(client, G760A_REG_SET_CNT);
+		data->act_cnt = g760a_read_value(client, G760A_REG_ACT_CNT);
+		data->fan_sta = g760a_read_value(client, G760A_REG_FAN_STA);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+			char *buf)
+{
+	struct g760a_data *data = g760a_update_client(dev);
+	unsigned int rpm = 0;
+
+	mutex_lock(&data->update_lock);
+	if (!(data->fan_sta & G760A_REG_FAN_STA_RPM_LOW))
+		rpm = rpm_from_cnt(data->act_cnt, data->clk, data->fan_div);
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute *da,
+			      char *buf)
+{
+	struct g760a_data *data = g760a_update_client(dev);
+
+	int fan_alarm = (data->fan_sta & G760A_REG_FAN_STA_RPM_OFF) ? 1 : 0;
+
+	return sprintf(buf, "%d\n", fan_alarm);
+}
+
+static ssize_t get_pwm(struct device *dev, struct device_attribute *da,
+		       char *buf)
+{
+	struct g760a_data *data = g760a_update_client(dev);
+
+	return sprintf(buf, "%d\n", PWM_FROM_CNT(data->set_cnt));
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
+		       const char *buf, size_t count)
+{
+	struct g760a_data *data = g760a_update_client(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->set_cnt = PWM_TO_CNT(clamp_val(val, 0, 255));
+	g760a_write_value(client, G760A_REG_SET_CNT, data->set_cnt);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL);
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
+
+static struct attribute *g760a_attrs[] = {
+	&dev_attr_pwm1.attr,
+	&dev_attr_fan1_input.attr,
+	&dev_attr_fan1_alarm.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(g760a);
+
+/*
+ * new-style driver model code
+ */
+
+static int g760a_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct g760a_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	data = devm_kzalloc(dev, sizeof(struct g760a_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* setup default configuration for now */
+	data->fan_div = G760A_DEFAULT_FAN_DIV;
+	data->clk = G760A_DEFAULT_CLK;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   g760a_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id g760a_id[] = {
+	{ "g760a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, g760a_id);
+
+static struct i2c_driver g760a_driver = {
+	.driver = {
+		.name	= "g760a",
+	},
+	.probe	  = g760a_probe,
+	.id_table = g760a_id,
+};
+
+module_i2c_driver(g760a_driver);
+
+MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
+MODULE_DESCRIPTION("GMT G760A driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
new file mode 100644
index 0000000..628be9c
--- /dev/null
+++ b/drivers/hwmon/g762.c
@@ -0,0 +1,1130 @@
+/*
+ * g762 - Driver for the Global Mixed-mode Technology Inc. fan speed
+ *        PWM controller chips from G762 family, i.e. G762 and G763
+ *
+ * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * This work is based on a basic version for 2.6.31 kernel developed
+ * by Olivier Mouchet for LaCie. Updates and correction have been
+ * performed to run on recent kernels. Additional features, like the
+ * ability to configure various characteristics via .dts file or
+ * board init file have been added. Detailed datasheet on which this
+ * development is based is available here:
+ *
+ *  http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf
+ *
+ * Headers from previous developments have been kept below:
+ *
+ * Copyright (c) 2009 LaCie
+ *
+ * Author: Olivier Mouchet <olivier.mouchet@gmail.com>
+ *
+ * based on g760a code written by Herbert Valerio Riedel <hvr@gnu.org>
+ * Copyright (C) 2007  Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * g762: minimal datasheet available at:
+ *       http://www.gmt.com.tw/product/datasheet/EDS-762_3.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.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.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/kernel.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/g762.h>
+
+#define DRVNAME "g762"
+
+static const struct i2c_device_id g762_id[] = {
+	{ "g762", 0 },
+	{ "g763", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, g762_id);
+
+enum g762_regs {
+	G762_REG_SET_CNT  = 0x00,
+	G762_REG_ACT_CNT  = 0x01,
+	G762_REG_FAN_STA  = 0x02,
+	G762_REG_SET_OUT  = 0x03,
+	G762_REG_FAN_CMD1 = 0x04,
+	G762_REG_FAN_CMD2 = 0x05,
+};
+
+/* Config register bits */
+#define G762_REG_FAN_CMD1_DET_FAN_FAIL  0x80 /* enable fan_fail signal */
+#define G762_REG_FAN_CMD1_DET_FAN_OOC   0x40 /* enable fan_out_of_control */
+#define G762_REG_FAN_CMD1_OUT_MODE      0x20 /* out mode: PWM or DC */
+#define G762_REG_FAN_CMD1_FAN_MODE      0x10 /* fan mode: closed/open-loop */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID1   0x08 /* clock divisor value */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID0   0x04
+#define G762_REG_FAN_CMD1_PWM_POLARITY  0x02 /* PWM polarity */
+#define G762_REG_FAN_CMD1_PULSE_PER_REV 0x01 /* pulse per fan revolution */
+
+#define G762_REG_FAN_CMD2_GEAR_MODE_1   0x08 /* fan gear mode */
+#define G762_REG_FAN_CMD2_GEAR_MODE_0   0x04
+#define G762_REG_FAN_CMD2_FAN_STARTV_1  0x02 /* fan startup voltage */
+#define G762_REG_FAN_CMD2_FAN_STARTV_0  0x01
+
+#define G762_REG_FAN_STA_FAIL           0x02 /* fan fail */
+#define G762_REG_FAN_STA_OOC            0x01 /* fan out of control */
+
+/* Config register values */
+#define G762_OUT_MODE_PWM            1
+#define G762_OUT_MODE_DC             0
+
+#define G762_FAN_MODE_CLOSED_LOOP    2
+#define G762_FAN_MODE_OPEN_LOOP      1
+
+#define G762_PWM_POLARITY_NEGATIVE   1
+#define G762_PWM_POLARITY_POSITIVE   0
+
+/* Register data is read (and cached) at most once per second. */
+#define G762_UPDATE_INTERVAL    HZ
+
+/*
+ * Extract pulse count per fan revolution value (2 or 4) from given
+ * FAN_CMD1 register value.
+ */
+#define G762_PULSE_FROM_REG(reg) \
+	((((reg) & G762_REG_FAN_CMD1_PULSE_PER_REV) + 1) << 1)
+
+/*
+ * Extract fan clock divisor (1, 2, 4 or 8) from given FAN_CMD1
+ * register value.
+ */
+#define G762_CLKDIV_FROM_REG(reg) \
+	(1 << (((reg) & (G762_REG_FAN_CMD1_CLK_DIV_ID0 |	\
+			 G762_REG_FAN_CMD1_CLK_DIV_ID1)) >> 2))
+
+/*
+ * Extract fan gear mode multiplier value (0, 2 or 4) from given
+ * FAN_CMD2 register value.
+ */
+#define G762_GEARMULT_FROM_REG(reg) \
+	(1 << (((reg) & (G762_REG_FAN_CMD2_GEAR_MODE_0 |	\
+			 G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
+
+struct g762_data {
+	struct device *hwmon_dev;
+	struct i2c_client *client;
+	struct clk *clk;
+
+	/* update mutex */
+	struct mutex update_lock;
+
+	/* board specific parameters. */
+	u32 clk_freq;
+
+	/* g762 register cache */
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+
+	u8 set_cnt;  /* controls fan rotation speed in closed-loop mode */
+	u8 act_cnt;  /* provides access to current fan RPM value */
+	u8 fan_sta;  /* bit 0: set when actual fan speed is more than
+		      *        25% outside requested fan speed
+		      * bit 1: set when no transition occurs on fan
+		      *        pin for 0.7s
+		      */
+	u8 set_out;  /* controls fan rotation speed in open-loop mode */
+	u8 fan_cmd1; /*   0: FG_PLS_ID0 FG pulses count per revolution
+		      *      0: 2 counts per revolution
+		      *      1: 4 counts per revolution
+		      *   1: PWM_POLARITY 1: negative_duty
+		      *                   0: positive_duty
+		      * 2,3: [FG_CLOCK_ID0, FG_CLK_ID1]
+		      *         00: Divide fan clock by 1
+		      *         01: Divide fan clock by 2
+		      *         10: Divide fan clock by 4
+		      *         11: Divide fan clock by 8
+		      *   4: FAN_MODE 1:closed-loop, 0:open-loop
+		      *   5: OUT_MODE 1:PWM, 0:DC
+		      *   6: DET_FAN_OOC enable "fan ooc" status
+		      *   7: DET_FAN_FAIL enable "fan fail" status
+		      */
+	u8 fan_cmd2; /* 0,1: FAN_STARTV 0,1,2,3 -> 0,32,64,96 dac_code
+		      * 2,3: FG_GEAR_MODE
+		      *         00: multiplier = 1
+		      *         01: multiplier = 2
+		      *         10: multiplier = 4
+		      *   4: Mask ALERT# (g763 only)
+		      */
+};
+
+/*
+ * Convert count value from fan controller register (FAN_SET_CNT) into fan
+ * speed RPM value. Note that the datasheet documents a basic formula;
+ * influence of additional parameters (fan clock divisor, fan gear mode)
+ * have been infered from examples in the datasheet and tests.
+ */
+static inline unsigned int rpm_from_cnt(u8 cnt, u32 clk_freq, u16 p,
+					u8 clk_div, u8 gear_mult)
+{
+	if (cnt == 0xff)  /* setting cnt to 255 stops the fan */
+		return 0;
+
+	return (clk_freq * 30 * gear_mult) / ((cnt ? cnt : 1) * p * clk_div);
+}
+
+/*
+ * Convert fan RPM value from sysfs into count value for fan controller
+ * register (FAN_SET_CNT).
+ */
+static inline unsigned char cnt_from_rpm(unsigned long rpm, u32 clk_freq, u16 p,
+					 u8 clk_div, u8 gear_mult)
+{
+	unsigned long f1 = clk_freq * 30 * gear_mult;
+	unsigned long f2 = p * clk_div;
+
+	if (!rpm)	/* to stop the fan, set cnt to 255 */
+		return 0xff;
+
+	rpm = clamp_val(rpm, f1 / (255 * f2), ULONG_MAX / f2);
+	return DIV_ROUND_CLOSEST(f1, rpm * f2);
+}
+
+/* helper to grab and cache data, at most one time per second */
+static struct g762_data *g762_update_client(struct device *dev)
+{
+	struct g762_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret = 0;
+
+	mutex_lock(&data->update_lock);
+	if (time_before(jiffies, data->last_updated + G762_UPDATE_INTERVAL) &&
+	    likely(data->valid))
+		goto out;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_SET_CNT);
+	if (ret < 0)
+		goto out;
+	data->set_cnt = ret;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_ACT_CNT);
+	if (ret < 0)
+		goto out;
+	data->act_cnt = ret;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_STA);
+	if (ret < 0)
+		goto out;
+	data->fan_sta = ret;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_SET_OUT);
+	if (ret < 0)
+		goto out;
+	data->set_out = ret;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD1);
+	if (ret < 0)
+		goto out;
+	data->fan_cmd1 = ret;
+
+	ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD2);
+	if (ret < 0)
+		goto out;
+	data->fan_cmd2 = ret;
+
+	data->last_updated = jiffies;
+	data->valid = true;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	if (ret < 0) /* upon error, encode it in return value */
+		data = ERR_PTR(ret);
+
+	return data;
+}
+
+/* helpers for writing hardware parameters */
+
+/*
+ * Set input clock frequency received on CLK pin of the chip. Accepted values
+ * are between 0 and 0xffffff. If zero is given, then default frequency
+ * (32,768Hz) is used. Note that clock frequency is a characteristic of the
+ * system but an internal parameter, i.e. value is not passed to the device.
+ */
+static int do_set_clk_freq(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = dev_get_drvdata(dev);
+
+	if (val > 0xffffff)
+		return -EINVAL;
+	if (!val)
+		val = 32768;
+
+	data->clk_freq = val;
+
+	return 0;
+}
+
+/* Set pwm mode. Accepts either 0 (PWM mode) or 1 (DC mode) */
+static int do_set_pwm_mode(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case G762_OUT_MODE_PWM:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_OUT_MODE;
+		break;
+	case G762_OUT_MODE_DC:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_OUT_MODE;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					data->fan_cmd1);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set fan clock divisor. Accepts either 1, 2, 4 or 8. */
+static int do_set_fan_div(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 1:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+		break;
+	case 2:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID0;
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+		break;
+	case 4:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID1;
+		break;
+	case 8:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID0;
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID1;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					data->fan_cmd1);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set fan gear mode. Accepts either 0, 1 or 2. */
+static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 0:
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+		break;
+	case 1:
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_GEAR_MODE_0;
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+		break;
+	case 2:
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_GEAR_MODE_1;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD2,
+					data->fan_cmd2);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set number of fan pulses per revolution. Accepts either 2 or 4. */
+static int do_set_fan_pulses(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 2:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PULSE_PER_REV;
+		break;
+	case 4:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_PULSE_PER_REV;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					data->fan_cmd1);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set fan mode. Accepts either 1 (open-loop) or 2 (closed-loop). */
+static int do_set_pwm_enable(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case G762_FAN_MODE_CLOSED_LOOP:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_FAN_MODE;
+		break;
+	case G762_FAN_MODE_OPEN_LOOP:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_FAN_MODE;
+		/*
+		 * BUG FIX: if SET_CNT register value is 255 then, for some
+		 * unknown reason, fan will not rotate as expected, no matter
+		 * the value of SET_OUT (to be specific, this seems to happen
+		 * only in PWM mode). To workaround this bug, we give SET_CNT
+		 * value of 254 if it is 255 when switching to open-loop.
+		 */
+		if (data->set_cnt == 0xff)
+			i2c_smbus_write_byte_data(data->client,
+						  G762_REG_SET_CNT, 254);
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					data->fan_cmd1);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set PWM polarity. Accepts either 0 (positive duty) or 1 (negative duty) */
+static int do_set_pwm_polarity(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case G762_PWM_POLARITY_POSITIVE:
+		data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PWM_POLARITY;
+		break;
+	case G762_PWM_POLARITY_NEGATIVE:
+		data->fan_cmd1 |=  G762_REG_FAN_CMD1_PWM_POLARITY;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					data->fan_cmd1);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/*
+ * Set pwm value. Accepts values between 0 (stops the fan) and
+ * 255 (full speed). This only makes sense in open-loop mode.
+ */
+static int do_set_pwm(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret;
+
+	if (val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	ret = i2c_smbus_write_byte_data(client, G762_REG_SET_OUT, val);
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/*
+ * Set fan RPM value. Can be called both in closed and open-loop mode
+ * but effect will only be seen after closed-loop mode is configured.
+ */
+static int do_set_fan_target(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	data->set_cnt = cnt_from_rpm(val, data->clk_freq,
+				     G762_PULSE_FROM_REG(data->fan_cmd1),
+				     G762_CLKDIV_FROM_REG(data->fan_cmd1),
+				     G762_GEARMULT_FROM_REG(data->fan_cmd2));
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_SET_CNT,
+					data->set_cnt);
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/* Set fan startup voltage. Accepted values are either 0, 1, 2 or 3. */
+static int do_set_fan_startv(struct device *dev, unsigned long val)
+{
+	struct g762_data *data = g762_update_client(dev);
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 0:
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+		break;
+	case 1:
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_0;
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+		break;
+	case 2:
+		data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_1;
+		break;
+	case 3:
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_0;
+		data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_1;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD2,
+					data->fan_cmd2);
+	data->valid = false;
+ out:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+#ifdef CONFIG_OF
+static const struct of_device_id g762_dt_match[] = {
+	{ .compatible = "gmt,g762" },
+	{ .compatible = "gmt,g763" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, g762_dt_match);
+
+/*
+ * Grab clock (a required property), enable it, get (fixed) clock frequency
+ * and store it. Note: upon success, clock has been prepared and enabled; it
+ * must later be unprepared and disabled (e.g. during module unloading) by a
+ * call to g762_of_clock_disable(). Note that a reference to clock is kept
+ * in our private data structure to be used in this function.
+ */
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+	struct g762_data *data;
+	unsigned long clk_freq;
+	struct clk *clk;
+	int ret;
+
+	if (!client->dev.of_node)
+		return 0;
+
+	clk = of_clk_get(client->dev.of_node, 0);
+	if (IS_ERR(clk)) {
+		dev_err(&client->dev, "failed to get clock\n");
+		return PTR_ERR(clk);
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(&client->dev, "failed to enable clock\n");
+		goto clk_put;
+	}
+
+	clk_freq = clk_get_rate(clk);
+	ret = do_set_clk_freq(&client->dev, clk_freq);
+	if (ret) {
+		dev_err(&client->dev, "invalid clock freq %lu\n", clk_freq);
+		goto clk_unprep;
+	}
+
+	data = i2c_get_clientdata(client);
+	data->clk = clk;
+
+	return 0;
+
+ clk_unprep:
+	clk_disable_unprepare(clk);
+
+ clk_put:
+	clk_put(clk);
+
+	return ret;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client)
+{
+	struct g762_data *data = i2c_get_clientdata(client);
+
+	if (!data->clk)
+		return;
+
+	clk_disable_unprepare(data->clk);
+	clk_put(data->clk);
+}
+
+static int g762_of_prop_import_one(struct i2c_client *client,
+				   const char *pname,
+				   int (*psetter)(struct device *dev,
+						  unsigned long val))
+{
+	int ret;
+	u32 pval;
+
+	if (of_property_read_u32(client->dev.of_node, pname, &pval))
+		return 0;
+
+	dev_dbg(&client->dev, "found %s (%d)\n", pname, pval);
+	ret = (*psetter)(&client->dev, pval);
+	if (ret)
+		dev_err(&client->dev, "unable to set %s (%d)\n", pname, pval);
+
+	return ret;
+}
+
+static int g762_of_prop_import(struct i2c_client *client)
+{
+	int ret;
+
+	if (!client->dev.of_node)
+		return 0;
+
+	ret = g762_of_prop_import_one(client, "fan_gear_mode",
+				      do_set_fan_gear_mode);
+	if (ret)
+		return ret;
+
+	ret = g762_of_prop_import_one(client, "pwm_polarity",
+				      do_set_pwm_polarity);
+	if (ret)
+		return ret;
+
+	return g762_of_prop_import_one(client, "fan_startv",
+				       do_set_fan_startv);
+}
+
+#else
+static int g762_of_prop_import(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client) { }
+#endif
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+static int g762_pdata_prop_import(struct i2c_client *client)
+{
+	struct g762_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret;
+
+	if (!pdata)
+		return 0;
+
+	ret = do_set_fan_gear_mode(&client->dev, pdata->fan_gear_mode);
+	if (ret)
+		return ret;
+
+	ret = do_set_pwm_polarity(&client->dev, pdata->pwm_polarity);
+	if (ret)
+		return ret;
+
+	ret = do_set_fan_startv(&client->dev, pdata->fan_startv);
+	if (ret)
+		return ret;
+
+	return do_set_clk_freq(&client->dev, pdata->clk_freq);
+}
+
+/*
+ * sysfs attributes
+ */
+
+/*
+ * Read function for fan1_input sysfs file. Return current fan RPM value, or
+ * 0 if fan is out of control.
+ */
+static ssize_t get_fan_rpm(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+	unsigned int rpm = 0;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	/* reverse logic: fan out of control reporting is enabled low */
+	if (data->fan_sta & G762_REG_FAN_STA_OOC) {
+		rpm = rpm_from_cnt(data->act_cnt, data->clk_freq,
+				   G762_PULSE_FROM_REG(data->fan_cmd1),
+				   G762_CLKDIV_FROM_REG(data->fan_cmd1),
+				   G762_GEARMULT_FROM_REG(data->fan_cmd2));
+	}
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n", rpm);
+}
+
+/*
+ * Read and write functions for pwm1_mode sysfs file. Get and set fan speed
+ * control mode i.e. PWM (1) or DC (0).
+ */
+static ssize_t get_pwm_mode(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n",
+		       !!(data->fan_cmd1 & G762_REG_FAN_CMD1_OUT_MODE));
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_pwm_mode(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/*
+ * Read and write functions for fan1_div sysfs file. Get and set fan
+ * controller prescaler value
+ */
+static ssize_t get_fan_div(struct device *dev,
+			   struct device_attribute *da, char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", G762_CLKDIV_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+			   struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_fan_div(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/*
+ * Read and write functions for fan1_pulses sysfs file. Get and set number
+ * of tachometer pulses per fan revolution.
+ */
+static ssize_t get_fan_pulses(struct device *dev,
+			      struct device_attribute *da, char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", G762_PULSE_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_pulses(struct device *dev,
+			      struct device_attribute *da,
+			      const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_fan_pulses(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/*
+ * Read and write functions for pwm1_enable. Get and set fan speed control mode
+ * (i.e. closed or open-loop).
+ *
+ * Following documentation about hwmon's sysfs interface, a pwm1_enable node
+ * should accept followings:
+ *
+ *  0 : no fan speed control (i.e. fan at full speed)
+ *  1 : manual fan speed control enabled (use pwm[1-*]) (open-loop)
+ *  2+: automatic fan speed control enabled (use fan[1-*]_target) (closed-loop)
+ *
+ * but we do not accept 0 as this mode is not natively supported by the chip
+ * and it is not emulated by g762 driver. -EINVAL is returned in this case.
+ */
+static ssize_t get_pwm_enable(struct device *dev,
+			      struct device_attribute *da, char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n",
+		       (!!(data->fan_cmd1 & G762_REG_FAN_CMD1_FAN_MODE)) + 1);
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+			      struct device_attribute *da,
+			      const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_pwm_enable(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/*
+ * Read and write functions for pwm1 sysfs file. Get and set pwm value
+ * (which affects fan speed) in open-loop mode. 0 stops the fan and 255
+ * makes it run at full speed.
+ */
+static ssize_t get_pwm(struct device *dev, struct device_attribute *da,
+		       char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->set_out);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
+		       const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_pwm(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/*
+ * Read and write function for fan1_target sysfs file. Get/set the fan speed in
+ * closed-loop mode. Speed is given as a RPM value; then the chip will regulate
+ * the fan speed using pulses from fan tachometer.
+ *
+ * Refer to rpm_from_cnt() implementation above to get info about count number
+ * calculation.
+ *
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+static ssize_t get_fan_target(struct device *dev, struct device_attribute *da,
+			      char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+	unsigned int rpm;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	rpm = rpm_from_cnt(data->set_cnt, data->clk_freq,
+			   G762_PULSE_FROM_REG(data->fan_cmd1),
+			   G762_CLKDIV_FROM_REG(data->fan_cmd1),
+			   G762_GEARMULT_FROM_REG(data->fan_cmd2));
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
+			      const char *buf, size_t count)
+{
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	ret = do_set_fan_target(dev, val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+/* read function for fan1_fault sysfs file. */
+static ssize_t get_fan_failure(struct device *dev, struct device_attribute *da,
+			       char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%u\n", !!(data->fan_sta & G762_REG_FAN_STA_FAIL));
+}
+
+/*
+ * read function for fan1_alarm sysfs file. Note that OOC condition is
+ * enabled low
+ */
+static ssize_t get_fan_ooc(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%u\n", !(data->fan_sta & G762_REG_FAN_STA_OOC));
+}
+
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, get_pwm_mode, set_pwm_mode);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+		   get_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, get_fan_ooc, NULL);
+static DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_failure, NULL);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
+		   get_fan_target, set_fan_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_fan_div, set_fan_div);
+static DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
+		   get_fan_pulses, set_fan_pulses);
+
+/* Driver data */
+static struct attribute *g762_attrs[] = {
+	&dev_attr_fan1_input.attr,
+	&dev_attr_fan1_alarm.attr,
+	&dev_attr_fan1_fault.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_div.attr,
+	&dev_attr_fan1_pulses.attr,
+	&dev_attr_pwm1.attr,
+	&dev_attr_pwm1_mode.attr,
+	&dev_attr_pwm1_enable.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(g762);
+
+/*
+ * Enable both fan failure detection and fan out of control protection. The
+ * function does not protect change/access to data structure; it must thus
+ * only be called during initialization.
+ */
+static inline int g762_fan_init(struct device *dev)
+{
+	struct g762_data *data = g762_update_client(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_FAIL;
+	data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_OOC;
+	data->valid = false;
+
+	return i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
+					 data->fan_cmd1);
+}
+
+static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct g762_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct g762_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Enable fan failure detection and fan out of control protection */
+	ret = g762_fan_init(dev);
+	if (ret)
+		return ret;
+
+	/* Get configuration via DT ... */
+	ret = g762_of_clock_enable(client);
+	if (ret)
+		return ret;
+	ret = g762_of_prop_import(client);
+	if (ret)
+		goto clock_dis;
+	/* ... or platform_data */
+	ret = g762_pdata_prop_import(client);
+	if (ret)
+		goto clock_dis;
+
+	data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+							    data, g762_groups);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto clock_dis;
+	}
+
+	return 0;
+
+ clock_dis:
+	g762_of_clock_disable(client);
+
+	return ret;
+}
+
+static int g762_remove(struct i2c_client *client)
+{
+	struct g762_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	g762_of_clock_disable(client);
+
+	return 0;
+}
+
+static struct i2c_driver g762_driver = {
+	.driver = {
+		.name = DRVNAME,
+		.of_match_table = of_match_ptr(g762_dt_match),
+	},
+	.probe	  = g762_probe,
+	.remove	  = g762_remove,
+	.id_table = g762_id,
+};
+
+module_i2c_driver(g762_driver);
+
+MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
+MODULE_DESCRIPTION("GMT G762/G763 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
new file mode 100644
index 0000000..0212c83
--- /dev/null
+++ b/drivers/hwmon/gl518sm.c
@@ -0,0 +1,682 @@
+/*
+ * gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring
+ * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
+ * Kyosti Malkki <kmalkki@cc.hut.fi>
+ * Copyright (C) 2004 Hong-Gunn Chew <hglinux@gunnet.org> and
+ * Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ *
+ * Ported to Linux 2.6 by Hong-Gunn Chew with the help of Jean Delvare
+ * and advice of Greg Kroah-Hartman.
+ *
+ * Notes about the port:
+ * Release 0x00 of the GL518SM chipset doesn't support reading of in0,
+ * in1 nor in2. The original driver had an ugly workaround to get them
+ * anyway (changing limits and watching alarms trigger and wear off).
+ * We did not keep that part of the original driver in the Linux 2.6
+ * version, since it was making the driver significantly more complex
+ * with no real benefit.
+ */
+
+#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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+
+enum chips { gl518sm_r00, gl518sm_r80 };
+
+/* Many GL518 constants specified below */
+
+/* The GL518 registers */
+#define GL518_REG_CHIP_ID	0x00
+#define GL518_REG_REVISION	0x01
+#define GL518_REG_VENDOR_ID	0x02
+#define GL518_REG_CONF		0x03
+#define GL518_REG_TEMP_IN	0x04
+#define GL518_REG_TEMP_MAX	0x05
+#define GL518_REG_TEMP_HYST	0x06
+#define GL518_REG_FAN_COUNT	0x07
+#define GL518_REG_FAN_LIMIT	0x08
+#define GL518_REG_VIN1_LIMIT	0x09
+#define GL518_REG_VIN2_LIMIT	0x0a
+#define GL518_REG_VIN3_LIMIT	0x0b
+#define GL518_REG_VDD_LIMIT	0x0c
+#define GL518_REG_VIN3		0x0d
+#define GL518_REG_MISC		0x0f
+#define GL518_REG_ALARM		0x10
+#define GL518_REG_MASK		0x11
+#define GL518_REG_INT		0x12
+#define GL518_REG_VIN2		0x13
+#define GL518_REG_VIN1		0x14
+#define GL518_REG_VDD		0x15
+
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ * Fixing this is just not worth it.
+ */
+
+#define RAW_FROM_REG(val)	val
+
+#define BOOL_FROM_REG(val)	((val) ? 0 : 1)
+#define BOOL_TO_REG(val)	((val) ? 0 : 1)
+
+#define TEMP_TO_REG(val)	clamp_val(((((val) < 0 ? \
+				(val) - 500 : \
+				(val) + 500) / 1000) + 119), 0, 255)
+#define TEMP_FROM_REG(val)	(((val) - 119) * 1000)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	long rpmdiv;
+	if (rpm == 0)
+		return 0;
+	rpmdiv = clamp_val(rpm, 1, 960000) * div;
+	return clamp_val((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
+}
+#define FAN_FROM_REG(val, div)	((val) == 0 ? 0 : (480000 / ((val) * (div))))
+
+#define IN_TO_REG(val)		clamp_val((((val) + 9) / 19), 0, 255)
+#define IN_FROM_REG(val)	((val) * 19)
+
+#define VDD_TO_REG(val)		clamp_val((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_FROM_REG(val)	(((val) * 95 + 2) / 4)
+
+#define DIV_FROM_REG(val)	(1 << (val))
+
+#define BEEP_MASK_TO_REG(val)	((val) & 0x7f & data->alarm_mask)
+#define BEEP_MASK_FROM_REG(val)	((val) & 0x7f)
+
+/* Each client has this additional data */
+struct gl518_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	enum chips type;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 voltage_in[4];	/* Register values; [0] = VDD */
+	u8 voltage_min[4];	/* Register values; [0] = VDD */
+	u8 voltage_max[4];	/* Register values; [0] = VDD */
+	u8 fan_in[2];
+	u8 fan_min[2];
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u8 fan_auto1;		/* Boolean */
+	u8 temp_in;		/* Register values */
+	u8 temp_max;		/* Register values */
+	u8 temp_hyst;		/* Register values */
+	u8 alarms;		/* Register value */
+	u8 alarm_mask;
+	u8 beep_mask;		/* Register value */
+	u8 beep_enable;		/* Boolean */
+};
+
+/*
+ * Registers 0x07 to 0x0c are word-sized, others are byte-sized
+ * GL518 uses a high-byte first convention, which is exactly opposite to
+ * the SMBus standard.
+ */
+static int gl518_read_value(struct i2c_client *client, u8 reg)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return i2c_smbus_read_word_swapped(client, reg);
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return i2c_smbus_write_word_swapped(client, reg, value);
+	else
+		return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct gl518_data *gl518_update_device(struct device *dev)
+{
+	struct gl518_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int val;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		dev_dbg(&client->dev, "Starting gl518 update\n");
+
+		data->alarms = gl518_read_value(client, GL518_REG_INT);
+		data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
+
+		val = gl518_read_value(client, GL518_REG_VDD_LIMIT);
+		data->voltage_min[0] = val & 0xff;
+		data->voltage_max[0] = (val >> 8) & 0xff;
+		val = gl518_read_value(client, GL518_REG_VIN1_LIMIT);
+		data->voltage_min[1] = val & 0xff;
+		data->voltage_max[1] = (val >> 8) & 0xff;
+		val = gl518_read_value(client, GL518_REG_VIN2_LIMIT);
+		data->voltage_min[2] = val & 0xff;
+		data->voltage_max[2] = (val >> 8) & 0xff;
+		val = gl518_read_value(client, GL518_REG_VIN3_LIMIT);
+		data->voltage_min[3] = val & 0xff;
+		data->voltage_max[3] = (val >> 8) & 0xff;
+
+		val = gl518_read_value(client, GL518_REG_FAN_COUNT);
+		data->fan_in[0] = (val >> 8) & 0xff;
+		data->fan_in[1] = val & 0xff;
+
+		val = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+		data->fan_min[0] = (val >> 8) & 0xff;
+		data->fan_min[1] = val & 0xff;
+
+		data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN);
+		data->temp_max =
+		    gl518_read_value(client, GL518_REG_TEMP_MAX);
+		data->temp_hyst =
+		    gl518_read_value(client, GL518_REG_TEMP_HYST);
+
+		val = gl518_read_value(client, GL518_REG_MISC);
+		data->fan_div[0] = (val >> 6) & 0x03;
+		data->fan_div[1] = (val >> 4) & 0x03;
+		data->fan_auto1  = (val >> 3) & 0x01;
+
+		data->alarms &= data->alarm_mask;
+
+		val = gl518_read_value(client, GL518_REG_CONF);
+		data->beep_enable = (val >> 2) & 1;
+
+		if (data->type != gl518sm_r00) {
+			data->voltage_in[0] =
+			    gl518_read_value(client, GL518_REG_VDD);
+			data->voltage_in[1] =
+			    gl518_read_value(client, GL518_REG_VIN1);
+			data->voltage_in[2] =
+			    gl518_read_value(client, GL518_REG_VIN2);
+		}
+		data->voltage_in[3] =
+		    gl518_read_value(client, GL518_REG_VIN3);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+#define show(type, suffix, value)					\
+static ssize_t show_##suffix(struct device *dev,			\
+			     struct device_attribute *attr, char *buf)	\
+{									\
+	struct gl518_data *data = gl518_update_device(dev);		\
+	return sprintf(buf, "%d\n", type##_FROM_REG(data->value));	\
+}
+
+show(TEMP, temp_input1, temp_in);
+show(TEMP, temp_max1, temp_max);
+show(TEMP, temp_hyst1, temp_hyst);
+show(BOOL, fan_auto1, fan_auto1);
+show(VDD, in_input0, voltage_in[0]);
+show(IN, in_input1, voltage_in[1]);
+show(IN, in_input2, voltage_in[2]);
+show(IN, in_input3, voltage_in[3]);
+show(VDD, in_min0, voltage_min[0]);
+show(IN, in_min1, voltage_min[1]);
+show(IN, in_min2, voltage_min[2]);
+show(IN, in_min3, voltage_min[3]);
+show(VDD, in_max0, voltage_max[0]);
+show(IN, in_max1, voltage_max[1]);
+show(IN, in_max2, voltage_max[2]);
+show(IN, in_max3, voltage_max[3]);
+show(RAW, alarms, alarms);
+show(BOOL, beep_enable, beep_enable);
+show(BEEP_MASK, beep_mask, beep_mask);
+
+static ssize_t show_fan_input(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct gl518_data *data = gl518_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_in[nr],
+					DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct gl518_data *data = gl518_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+					DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct gl518_data *data = gl518_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+#define set(type, suffix, value, reg)					\
+static ssize_t set_##suffix(struct device *dev,				\
+			    struct device_attribute *attr,		\
+			    const char *buf, size_t count)		\
+{									\
+	struct gl518_data *data = dev_get_drvdata(dev);			\
+	struct i2c_client *client = data->client;			\
+	long val;							\
+	int err = kstrtol(buf, 10, &val);				\
+	if (err)							\
+		return err;						\
+									\
+	mutex_lock(&data->update_lock);					\
+	data->value = type##_TO_REG(val);				\
+	gl518_write_value(client, reg, data->value);			\
+	mutex_unlock(&data->update_lock);				\
+	return count;							\
+}
+
+#define set_bits(type, suffix, value, reg, mask, shift)			\
+static ssize_t set_##suffix(struct device *dev,				\
+			    struct device_attribute *attr,		\
+			    const char *buf, size_t count)		\
+{									\
+	struct gl518_data *data = dev_get_drvdata(dev);			\
+	struct i2c_client *client = data->client;			\
+	int regvalue;							\
+	unsigned long val;						\
+	int err = kstrtoul(buf, 10, &val);				\
+	if (err)							\
+		return err;						\
+									\
+	mutex_lock(&data->update_lock);					\
+	regvalue = gl518_read_value(client, reg);			\
+	data->value = type##_TO_REG(val);				\
+	regvalue = (regvalue & ~mask) | (data->value << shift);		\
+	gl518_write_value(client, reg, regvalue);			\
+	mutex_unlock(&data->update_lock);				\
+	return count;							\
+}
+
+#define set_low(type, suffix, value, reg)				\
+	set_bits(type, suffix, value, reg, 0x00ff, 0)
+#define set_high(type, suffix, value, reg)				\
+	set_bits(type, suffix, value, reg, 0xff00, 8)
+
+set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX);
+set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST);
+set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3);
+set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT);
+set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT);
+set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT);
+set_low(IN, in_min3, voltage_min[3], GL518_REG_VIN3_LIMIT);
+set_high(VDD, in_max0, voltage_max[0], GL518_REG_VDD_LIMIT);
+set_high(IN, in_max1, voltage_max[1], GL518_REG_VIN1_LIMIT);
+set_high(IN, in_max2, voltage_max[2], GL518_REG_VIN2_LIMIT);
+set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT);
+set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2);
+set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM);
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gl518_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	int regvalue;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	regvalue = (regvalue & (0xff << (8 * nr)))
+		 | (data->fan_min[nr] << (8 * (1 - nr)));
+	gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue);
+
+	data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
+	if (data->fan_min[nr] == 0)
+		data->alarm_mask &= ~(0x20 << nr);
+	else
+		data->alarm_mask |= (0x20 << nr);
+	data->beep_mask &= data->alarm_mask;
+	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gl518_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = to_sensor_dev_attr(attr)->index;
+	int regvalue;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	switch (val) {
+	case 1:
+		val = 0;
+		break;
+	case 2:
+		val = 1;
+		break;
+	case 4:
+		val = 2;
+		break;
+	case 8:
+		val = 3;
+		break;
+	default:
+		dev_err(dev,
+			"Invalid fan clock divider %lu, choose one of 1, 2, 4 or 8\n",
+			val);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	regvalue = gl518_read_value(client, GL518_REG_MISC);
+	data->fan_div[nr] = val;
+	regvalue = (regvalue & ~(0xc0 >> (2 * nr)))
+		 | (data->fan_div[nr] << (6 - 2 * nr));
+	gl518_write_value(client, GL518_REG_MISC, regvalue);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1);
+static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO,
+	show_temp_hyst1, set_temp_hyst1);
+static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO,
+	show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO,
+	show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO,
+	show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO,
+	show_fan_div, set_fan_div, 1);
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);
+static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);
+static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);
+static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL);
+static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0);
+static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1);
+static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2);
+static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3);
+static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0);
+static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1);
+static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2);
+static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
+	show_beep_enable, set_beep_enable);
+static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
+	show_beep_mask, set_beep_mask);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct gl518_data *data = gl518_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct gl518_data *data = gl518_update_device(dev);
+	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct gl518_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	unsigned long bit;
+	int err;
+
+	err = kstrtoul(buf, 10, &bit);
+	if (err)
+		return err;
+
+	if (bit & ~1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
+	if (bit)
+		data->beep_mask |= (1 << bitnr);
+	else
+		data->beep_mask &= ~(1 << bitnr);
+	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 3);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 4);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 5);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 6);
+
+static struct attribute *gl518_attributes[] = {
+	&dev_attr_in3_input.attr,
+	&dev_attr_in0_min.attr,
+	&dev_attr_in1_min.attr,
+	&dev_attr_in2_min.attr,
+	&dev_attr_in3_min.attr,
+	&dev_attr_in0_max.attr,
+	&dev_attr_in1_max.attr,
+	&dev_attr_in2_max.attr,
+	&dev_attr_in3_max.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_beep.dev_attr.attr,
+	&sensor_dev_attr_in1_beep.dev_attr.attr,
+	&sensor_dev_attr_in2_beep.dev_attr.attr,
+	&sensor_dev_attr_in3_beep.dev_attr.attr,
+
+	&dev_attr_fan1_auto.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_beep.dev_attr.attr,
+	&sensor_dev_attr_fan2_beep.dev_attr.attr,
+
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_max_hyst.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_beep.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&dev_attr_beep_enable.attr,
+	&dev_attr_beep_mask.attr,
+	NULL
+};
+
+static const struct attribute_group gl518_group = {
+	.attrs = gl518_attributes,
+};
+
+static struct attribute *gl518_attributes_r80[] = {
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	&dev_attr_in2_input.attr,
+	NULL
+};
+
+static const struct attribute_group gl518_group_r80 = {
+	.attrs = gl518_attributes_r80,
+};
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int rev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	/* Now, we do the remaining detection. */
+	if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
+	 || (gl518_read_value(client, GL518_REG_CONF) & 0x80))
+		return -ENODEV;
+
+	/* Determine the chip type. */
+	rev = gl518_read_value(client, GL518_REG_REVISION);
+	if (rev != 0x00 && rev != 0x80)
+		return -ENODEV;
+
+	strlcpy(info->type, "gl518sm", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+/*
+ * Called when we have found a new GL518SM.
+ * Note that we preserve D4:NoFan2 and D2:beep_enable.
+ */
+static void gl518_init_client(struct i2c_client *client)
+{
+	/* Make sure we leave D7:Reset untouched */
+	u8 regvalue = gl518_read_value(client, GL518_REG_CONF) & 0x7f;
+
+	/* Comparator mode (D3=0), standby mode (D6=0) */
+	gl518_write_value(client, GL518_REG_CONF, (regvalue &= 0x37));
+
+	/* Never interrupts */
+	gl518_write_value(client, GL518_REG_MASK, 0x00);
+
+	/* Clear status register (D5=1), start (D6=1) */
+	gl518_write_value(client, GL518_REG_CONF, 0x20 | regvalue);
+	gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue);
+}
+
+static int gl518_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct gl518_data *data;
+	int revision;
+
+	data = devm_kzalloc(dev, sizeof(struct gl518_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	revision = gl518_read_value(client, GL518_REG_REVISION);
+	data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the GL518SM chip */
+	data->alarm_mask = 0xff;
+	gl518_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &gl518_group;
+	if (data->type == gl518sm_r80)
+		data->groups[1] = &gl518_group_r80;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id gl518_id[] = {
+	{ "gl518sm", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, gl518_id);
+
+static struct i2c_driver gl518_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "gl518sm",
+	},
+	.probe		= gl518_probe,
+	.id_table	= gl518_id,
+	.detect		= gl518_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(gl518_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	"Kyosti Malkki <kmalkki@cc.hut.fi> and "
+	"Hong-Gunn Chew <hglinux@gunnet.org>");
+MODULE_DESCRIPTION("GL518SM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
new file mode 100644
index 0000000..84e0994
--- /dev/null
+++ b/drivers/hwmon/gl520sm.c
@@ -0,0 +1,939 @@
+/*
+ * gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
+ *			     Kyösti Mälkki <kmalkki@cc.hut.fi>
+ * Copyright (c) 2005	Maarten Deprez <maartendeprez@users.sourceforge.net>
+ *
+ * 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/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Type of the extra sensor */
+static unsigned short extra_sensor_type;
+module_param(extra_sensor_type, ushort, 0);
+MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)");
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+
+/*
+ * Many GL520 constants specified below
+ * One of the inputs can be configured as either temp or voltage.
+ * That's why _TEMP2 and _IN4 access the same register
+ */
+
+/* The GL520 registers */
+#define GL520_REG_CHIP_ID		0x00
+#define GL520_REG_REVISION		0x01
+#define GL520_REG_CONF			0x03
+#define GL520_REG_MASK			0x11
+
+#define GL520_REG_VID_INPUT		0x02
+
+static const u8 GL520_REG_IN_INPUT[]	= { 0x15, 0x14, 0x13, 0x0d, 0x0e };
+static const u8 GL520_REG_IN_LIMIT[]	= { 0x0c, 0x09, 0x0a, 0x0b };
+static const u8 GL520_REG_IN_MIN[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x18 };
+static const u8 GL520_REG_IN_MAX[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x17 };
+
+static const u8 GL520_REG_TEMP_INPUT[]		= { 0x04, 0x0e };
+static const u8 GL520_REG_TEMP_MAX[]		= { 0x05, 0x17 };
+static const u8 GL520_REG_TEMP_MAX_HYST[]	= { 0x06, 0x18 };
+
+#define GL520_REG_FAN_INPUT		0x07
+#define GL520_REG_FAN_MIN		0x08
+#define GL520_REG_FAN_DIV		0x0f
+#define GL520_REG_FAN_OFF		GL520_REG_FAN_DIV
+
+#define GL520_REG_ALARMS		0x12
+#define GL520_REG_BEEP_MASK		0x10
+#define GL520_REG_BEEP_ENABLE		GL520_REG_CONF
+
+/* Client data */
+struct gl520_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	char valid;		/* zero until the following fields are valid */
+	unsigned long last_updated;	/* in jiffies */
+
+	u8 vid;
+	u8 vrm;
+	u8 in_input[5];		/* [0] = VVD */
+	u8 in_min[5];		/* [0] = VDD */
+	u8 in_max[5];		/* [0] = VDD */
+	u8 fan_input[2];
+	u8 fan_min[2];
+	u8 fan_div[2];
+	u8 fan_off;
+	u8 temp_input[2];
+	u8 temp_max[2];
+	u8 temp_max_hyst[2];
+	u8 alarms;
+	u8 beep_enable;
+	u8 beep_mask;
+	u8 alarm_mask;
+	u8 two_temps;
+};
+
+/*
+ * Registers 0x07 to 0x0c are word-sized, others are byte-sized
+ * GL520 uses a high-byte first convention
+ */
+static int gl520_read_value(struct i2c_client *client, u8 reg)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return i2c_smbus_read_word_swapped(client, reg);
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return i2c_smbus_write_word_swapped(client, reg, value);
+	else
+		return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct gl520_data *gl520_update_device(struct device *dev)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int val, i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting gl520sm update\n");
+
+		data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
+		data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+		data->vid = gl520_read_value(client,
+					     GL520_REG_VID_INPUT) & 0x1f;
+
+		for (i = 0; i < 4; i++) {
+			data->in_input[i] = gl520_read_value(client,
+							GL520_REG_IN_INPUT[i]);
+			val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
+			data->in_min[i] = val & 0xff;
+			data->in_max[i] = (val >> 8) & 0xff;
+		}
+
+		val = gl520_read_value(client, GL520_REG_FAN_INPUT);
+		data->fan_input[0] = (val >> 8) & 0xff;
+		data->fan_input[1] = val & 0xff;
+
+		val = gl520_read_value(client, GL520_REG_FAN_MIN);
+		data->fan_min[0] = (val >> 8) & 0xff;
+		data->fan_min[1] = val & 0xff;
+
+		data->temp_input[0] = gl520_read_value(client,
+						GL520_REG_TEMP_INPUT[0]);
+		data->temp_max[0] = gl520_read_value(client,
+						GL520_REG_TEMP_MAX[0]);
+		data->temp_max_hyst[0] = gl520_read_value(client,
+						GL520_REG_TEMP_MAX_HYST[0]);
+
+		val = gl520_read_value(client, GL520_REG_FAN_DIV);
+		data->fan_div[0] = (val >> 6) & 0x03;
+		data->fan_div[1] = (val >> 4) & 0x03;
+		data->fan_off = (val >> 2) & 0x01;
+
+		data->alarms &= data->alarm_mask;
+
+		val = gl520_read_value(client, GL520_REG_CONF);
+		data->beep_enable = !((val >> 2) & 1);
+
+		/* Temp1 and Vin4 are the same input */
+		if (data->two_temps) {
+			data->temp_input[1] = gl520_read_value(client,
+						GL520_REG_TEMP_INPUT[1]);
+			data->temp_max[1] = gl520_read_value(client,
+						GL520_REG_TEMP_MAX[1]);
+			data->temp_max_hyst[1] = gl520_read_value(client,
+						GL520_REG_TEMP_MAX_HYST[1]);
+		} else {
+			data->in_input[4] = gl520_read_value(client,
+						GL520_REG_IN_INPUT[4]);
+			data->in_min[4] = gl520_read_value(client,
+						GL520_REG_IN_MIN[4]);
+			data->in_max[4] = gl520_read_value(client,
+						GL520_REG_IN_MAX[4]);
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct gl520_data *data = gl520_update_device(dev);
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
+
+#define VDD_FROM_REG(val)	DIV_ROUND_CLOSEST((val) * 95, 4)
+#define VDD_CLAMP(val)		clamp_val(val, 0, 255 * 95 / 4)
+#define VDD_TO_REG(val)		DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95)
+
+#define IN_FROM_REG(val)	((val) * 19)
+#define IN_CLAMP(val)		clamp_val(val, 0, 255 * 19)
+#define IN_TO_REG(val)		DIV_ROUND_CLOSEST(IN_CLAMP(val), 19)
+
+static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+	u8 r = data->in_input[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t get_in_min(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+	u8 r = data->in_min[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t get_in_max(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+	u8 r = data->in_max[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	u8 r;
+	long v;
+	int err;
+
+	err = kstrtol(buf, 10, &v);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	if (n == 0)
+		r = VDD_TO_REG(v);
+	else
+		r = IN_TO_REG(v);
+
+	data->in_min[n] = r;
+
+	if (n < 4)
+		gl520_write_value(client, GL520_REG_IN_MIN[n],
+				  (gl520_read_value(client, GL520_REG_IN_MIN[n])
+				   & ~0xff) | r);
+	else
+		gl520_write_value(client, GL520_REG_IN_MIN[n], r);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	u8 r;
+	long v;
+	int err;
+
+	err = kstrtol(buf, 10, &v);
+	if (err)
+		return err;
+
+	if (n == 0)
+		r = VDD_TO_REG(v);
+	else
+		r = IN_TO_REG(v);
+
+	mutex_lock(&data->update_lock);
+
+	data->in_max[n] = r;
+
+	if (n < 4)
+		gl520_write_value(client, GL520_REG_IN_MAX[n],
+				  (gl520_read_value(client, GL520_REG_IN_MAX[n])
+				   & ~0xff00) | (r << 8));
+	else
+		gl520_write_value(client, GL520_REG_IN_MAX[n], r);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, get_in_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, get_in_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, get_in_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, get_in_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, get_in_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
+		get_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
+		get_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
+		get_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
+		get_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
+		get_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+		get_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
+		get_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
+		get_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
+		get_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
+		get_in_max, set_in_max, 4);
+
+#define DIV_FROM_REG(val) (1 << (val))
+#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
+
+#define FAN_BASE(div)		(480000 >> (div))
+#define FAN_CLAMP(val, div)	clamp_val(val, FAN_BASE(div) / 255, \
+					  FAN_BASE(div))
+#define FAN_TO_REG(val, div)	((val) == 0 ? 0 : \
+				 DIV_ROUND_CLOSEST(480000, \
+						FAN_CLAMP(val, div) << (div)))
+
+static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n],
+						 data->fan_div[n]));
+}
+
+static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n],
+						 data->fan_div[n]));
+}
+
+static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n]));
+}
+
+static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct gl520_data *data = gl520_update_device(dev);
+	return sprintf(buf, "%d\n", data->fan_off);
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	u8 r;
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	r = FAN_TO_REG(v, data->fan_div[n]);
+	data->fan_min[n] = r;
+
+	if (n == 0)
+		gl520_write_value(client, GL520_REG_FAN_MIN,
+				  (gl520_read_value(client, GL520_REG_FAN_MIN)
+				   & ~0xff00) | (r << 8));
+	else
+		gl520_write_value(client, GL520_REG_FAN_MIN,
+				  (gl520_read_value(client, GL520_REG_FAN_MIN)
+				   & ~0xff) | r);
+
+	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+	if (data->fan_min[n] == 0)
+		data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
+	else
+		data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
+	data->beep_mask &= data->alarm_mask;
+	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	u8 r;
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	switch (v) {
+	case 1:
+		r = 0;
+		break;
+	case 2:
+		r = 1;
+		break;
+	case 4:
+		r = 2;
+		break;
+	case 8:
+		r = 3;
+		break;
+	default:
+		dev_err(&client->dev,
+	"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->fan_div[n] = r;
+
+	if (n == 0)
+		gl520_write_value(client, GL520_REG_FAN_DIV,
+				  (gl520_read_value(client, GL520_REG_FAN_DIV)
+				   & ~0xc0) | (r << 6));
+	else
+		gl520_write_value(client, GL520_REG_FAN_DIV,
+				  (gl520_read_value(client, GL520_REG_FAN_DIV)
+				   & ~0x30) | (r << 4));
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 r;
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	r = (v ? 1 : 0);
+
+	mutex_lock(&data->update_lock);
+	data->fan_off = r;
+	gl520_write_value(client, GL520_REG_FAN_OFF,
+			  (gl520_read_value(client, GL520_REG_FAN_OFF)
+			   & ~0x0c) | (r << 2));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+		get_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+		get_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		get_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		get_fan_div, set_fan_div, 1);
+static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
+		get_fan_off, set_fan_off);
+
+#define TEMP_FROM_REG(val)	(((val) - 130) * 1000)
+#define TEMP_CLAMP(val)		clamp_val(val, -130000, 125000)
+#define TEMP_TO_REG(val)	(DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 130)
+
+static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n]));
+}
+
+static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n]));
+}
+
+static ssize_t get_temp_max_hyst(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int n = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	long v;
+	int err;
+
+	err = kstrtol(buf, 10, &v);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[n] = TEMP_TO_REG(v);
+	gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
+				 *attr, const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int n = to_sensor_dev_attr(attr)->index;
+	long v;
+	int err;
+
+	err = kstrtol(buf, 10, &v);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max_hyst[n] = TEMP_TO_REG(v);
+	gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n],
+			  data->temp_max_hyst[n]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		get_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+		get_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		get_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+		get_temp_max_hyst, set_temp_max_hyst, 1);
+
+static ssize_t get_alarms(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct gl520_data *data = gl520_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t get_beep_enable(struct device *dev, struct device_attribute
+			       *attr, char *buf)
+{
+	struct gl520_data *data = gl520_update_device(dev);
+	return sprintf(buf, "%d\n", data->beep_enable);
+}
+
+static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct gl520_data *data = gl520_update_device(dev);
+	return sprintf(buf, "%d\n", data->beep_mask);
+}
+
+static ssize_t set_beep_enable(struct device *dev, struct device_attribute
+			       *attr, const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 r;
+	unsigned long v;
+	int err;
+
+	err = kstrtoul(buf, 10, &v);
+	if (err)
+		return err;
+
+	r = (v ? 0 : 1);
+
+	mutex_lock(&data->update_lock);
+	data->beep_enable = !r;
+	gl520_write_value(client, GL520_REG_BEEP_ENABLE,
+			  (gl520_read_value(client, GL520_REG_BEEP_ENABLE)
+			   & ~0x04) | (r << 2));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long r;
+	int err;
+
+	err = kstrtoul(buf, 10, &r);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	r &= data->alarm_mask;
+	data->beep_mask = r;
+	gl520_write_value(client, GL520_REG_BEEP_MASK, r);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+		get_beep_enable, set_beep_enable);
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+		get_beep_mask, set_beep_mask);
+
+static ssize_t get_alarm(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	int bit_nr = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", (data->alarms >> bit_nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, get_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, get_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, get_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, get_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, get_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, get_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, get_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, get_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, get_alarm, NULL, 7);
+
+static ssize_t get_beep(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct gl520_data *data = gl520_update_device(dev);
+
+	return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct gl520_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	unsigned long bit;
+
+	int err;
+
+	err = kstrtoul(buf, 10, &bit);
+	if (err)
+		return err;
+	if (bit & ~1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+	if (bit)
+		data->beep_mask |= (1 << bitnr);
+	else
+		data->beep_mask &= ~(1 << bitnr);
+	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 3);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 4);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 5);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 6);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
+
+static struct attribute *gl520_attributes[] = {
+	&dev_attr_cpu0_vid.attr,
+
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_beep.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_beep.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_beep.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_beep.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_beep.dev_attr.attr,
+	&dev_attr_fan1_off.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_beep.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&dev_attr_beep_enable.attr,
+	&dev_attr_beep_mask.attr,
+	NULL
+};
+
+static const struct attribute_group gl520_group = {
+	.attrs = gl520_attributes,
+};
+
+static struct attribute *gl520_attributes_in4[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_beep.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *gl520_attributes_temp2[] = {
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_beep.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group gl520_group_in4 = {
+	.attrs = gl520_attributes_in4,
+};
+
+static const struct attribute_group gl520_group_temp2 = {
+	.attrs = gl520_attributes_temp2,
+};
+
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	/* Determine the chip type. */
+	if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
+	    ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
+	    ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
+		dev_dbg(&client->dev, "Unknown chip type, skipping\n");
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "gl520sm", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+/* Called when we have found a new GL520SM. */
+static void gl520_init_client(struct i2c_client *client)
+{
+	struct gl520_data *data = i2c_get_clientdata(client);
+	u8 oldconf, conf;
+
+	conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
+
+	data->alarm_mask = 0xff;
+	data->vrm = vid_which_vrm();
+
+	if (extra_sensor_type == 1)
+		conf &= ~0x10;
+	else if (extra_sensor_type == 2)
+		conf |= 0x10;
+	data->two_temps = !(conf & 0x10);
+
+	/* If IRQ# is disabled, we can safely force comparator mode */
+	if (!(conf & 0x20))
+		conf &= 0xf7;
+
+	/* Enable monitoring if needed */
+	conf |= 0x40;
+
+	if (conf != oldconf)
+		gl520_write_value(client, GL520_REG_CONF, conf);
+
+	gl520_update_device(&(client->dev));
+
+	if (data->fan_min[0] == 0)
+		data->alarm_mask &= ~0x20;
+	if (data->fan_min[1] == 0)
+		data->alarm_mask &= ~0x40;
+
+	data->beep_mask &= data->alarm_mask;
+	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
+}
+
+static int gl520_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct gl520_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct gl520_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+	data->client = client;
+
+	/* Initialize the GL520SM chip */
+	gl520_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &gl520_group;
+
+	if (data->two_temps)
+		data->groups[1] = &gl520_group_temp2;
+	else
+		data->groups[1] = &gl520_group_in4;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id gl520_id[] = {
+	{ "gl520sm", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, gl520_id);
+
+static struct i2c_driver gl520_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "gl520sm",
+	},
+	.probe		= gl520_probe,
+	.id_table	= gl520_id,
+	.detect		= gl520_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(gl520_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
+	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
+MODULE_DESCRIPTION("GL520SM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
new file mode 100644
index 0000000..685568b
--- /dev/null
+++ b/drivers/hwmon/gpio-fan.c
@@ -0,0 +1,677 @@
+/*
+ * gpio-fan.c - Hwmon driver for fans connected to GPIO lines.
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/gpio.h>
+#include <linux/gpio-fan.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/thermal.h>
+
+struct gpio_fan_data {
+	struct platform_device	*pdev;
+	struct device		*hwmon_dev;
+	/* Cooling device if any */
+	struct thermal_cooling_device *cdev;
+	struct mutex		lock; /* lock GPIOs operations. */
+	int			num_ctrl;
+	unsigned		*ctrl;
+	int			num_speed;
+	struct gpio_fan_speed	*speed;
+	int			speed_index;
+#ifdef CONFIG_PM_SLEEP
+	int			resume_speed;
+#endif
+	bool			pwm_enable;
+	struct gpio_fan_alarm	*alarm;
+	struct work_struct	alarm_work;
+};
+
+/*
+ * Alarm GPIO.
+ */
+
+static void fan_alarm_notify(struct work_struct *ws)
+{
+	struct gpio_fan_data *fan_data =
+		container_of(ws, struct gpio_fan_data, alarm_work);
+
+	sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
+	kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
+{
+	struct gpio_fan_data *fan_data = dev_id;
+
+	schedule_work(&fan_data->alarm_work);
+
+	return IRQ_NONE;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	struct gpio_fan_alarm *alarm = fan_data->alarm;
+	int value = gpio_get_value_cansleep(alarm->gpio);
+
+	if (alarm->active_low)
+		value = !value;
+
+	return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
+
+static int fan_alarm_init(struct gpio_fan_data *fan_data,
+			  struct gpio_fan_alarm *alarm)
+{
+	int err;
+	int alarm_irq;
+	struct platform_device *pdev = fan_data->pdev;
+
+	fan_data->alarm = alarm;
+
+	err = devm_gpio_request(&pdev->dev, alarm->gpio, "GPIO fan alarm");
+	if (err)
+		return err;
+
+	err = gpio_direction_input(alarm->gpio);
+	if (err)
+		return err;
+
+	/*
+	 * If the alarm GPIO don't support interrupts, just leave
+	 * without initializing the fail notification support.
+	 */
+	alarm_irq = gpio_to_irq(alarm->gpio);
+	if (alarm_irq < 0)
+		return 0;
+
+	INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
+	irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
+	err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
+			       IRQF_SHARED, "GPIO fan alarm", fan_data);
+	return err;
+}
+
+/*
+ * Control GPIOs.
+ */
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
+{
+	int i;
+
+	for (i = 0; i < fan_data->num_ctrl; i++)
+		gpio_set_value_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+}
+
+static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
+{
+	int i;
+	int ctrl_val = 0;
+
+	for (i = 0; i < fan_data->num_ctrl; i++) {
+		int value;
+
+		value = gpio_get_value_cansleep(fan_data->ctrl[i]);
+		ctrl_val |= (value << i);
+	}
+	return ctrl_val;
+}
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
+{
+	if (fan_data->speed_index == speed_index)
+		return;
+
+	__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
+	fan_data->speed_index = speed_index;
+}
+
+static int get_fan_speed_index(struct gpio_fan_data *fan_data)
+{
+	int ctrl_val = __get_fan_ctrl(fan_data);
+	int i;
+
+	for (i = 0; i < fan_data->num_speed; i++)
+		if (fan_data->speed[i].ctrl_val == ctrl_val)
+			return i;
+
+	dev_warn(&fan_data->pdev->dev,
+		 "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
+
+	return -ENODEV;
+}
+
+static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm)
+{
+	struct gpio_fan_speed *speed = fan_data->speed;
+	int i;
+
+	for (i = 0; i < fan_data->num_speed; i++)
+		if (speed[i].rpm >= rpm)
+			return i;
+
+	return fan_data->num_speed - 1;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long pwm;
+	int speed_index;
+	int ret = count;
+
+	if (kstrtoul(buf, 10, &pwm) || pwm > 255)
+		return -EINVAL;
+
+	mutex_lock(&fan_data->lock);
+
+	if (!fan_data->pwm_enable) {
+		ret = -EPERM;
+		goto exit_unlock;
+	}
+
+	speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
+	set_fan_speed(fan_data, speed_index);
+
+exit_unlock:
+	mutex_unlock(&fan_data->lock);
+
+	return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->pwm_enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	if (fan_data->pwm_enable == val)
+		return count;
+
+	mutex_lock(&fan_data->lock);
+
+	fan_data->pwm_enable = val;
+
+	/* Disable manual control mode: set fan at full speed. */
+	if (val == 0)
+		set_fan_speed(fan_data, fan_data->num_speed - 1);
+
+	mutex_unlock(&fan_data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_mode(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0\n");
+}
+
+static ssize_t show_rpm_min(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
+}
+
+static ssize_t show_rpm_max(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n",
+		       fan_data->speed[fan_data->num_speed - 1].rpm);
+}
+
+static ssize_t show_rpm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
+}
+
+static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long rpm;
+	int ret = count;
+
+	if (kstrtoul(buf, 10, &rpm))
+		return -EINVAL;
+
+	mutex_lock(&fan_data->lock);
+
+	if (!fan_data->pwm_enable) {
+		ret = -EPERM;
+		goto exit_unlock;
+	}
+
+	set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
+
+exit_unlock:
+	mutex_unlock(&fan_data->lock);
+
+	return ret;
+}
+
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+		   show_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL);
+static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL);
+static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
+static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
+
+static umode_t gpio_fan_is_visible(struct kobject *kobj,
+				   struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct gpio_fan_data *data = dev_get_drvdata(dev);
+
+	if (index == 0 && !data->alarm)
+		return 0;
+	if (index > 0 && !data->ctrl)
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute *gpio_fan_attributes[] = {
+	&dev_attr_fan1_alarm.attr,		/* 0 */
+	&dev_attr_pwm1.attr,			/* 1 */
+	&dev_attr_pwm1_enable.attr,
+	&dev_attr_pwm1_mode.attr,
+	&dev_attr_fan1_input.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_min.attr,
+	&dev_attr_fan1_max.attr,
+	NULL
+};
+
+static const struct attribute_group gpio_fan_group = {
+	.attrs = gpio_fan_attributes,
+	.is_visible = gpio_fan_is_visible,
+};
+
+static const struct attribute_group *gpio_fan_groups[] = {
+	&gpio_fan_group,
+	NULL
+};
+
+static int fan_ctrl_init(struct gpio_fan_data *fan_data,
+			 struct gpio_fan_platform_data *pdata)
+{
+	struct platform_device *pdev = fan_data->pdev;
+	int num_ctrl = pdata->num_ctrl;
+	unsigned *ctrl = pdata->ctrl;
+	int i, err;
+
+	for (i = 0; i < num_ctrl; i++) {
+		err = devm_gpio_request(&pdev->dev, ctrl[i],
+					"GPIO fan control");
+		if (err)
+			return err;
+
+		err = gpio_direction_output(ctrl[i],
+					    gpio_get_value_cansleep(ctrl[i]));
+		if (err)
+			return err;
+	}
+
+	fan_data->num_ctrl = num_ctrl;
+	fan_data->ctrl = ctrl;
+	fan_data->num_speed = pdata->num_speed;
+	fan_data->speed = pdata->speed;
+	fan_data->pwm_enable = true; /* Enable manual fan speed control. */
+	fan_data->speed_index = get_fan_speed_index(fan_data);
+	if (fan_data->speed_index < 0)
+		return fan_data->speed_index;
+
+	return 0;
+}
+
+static int gpio_fan_get_max_state(struct thermal_cooling_device *cdev,
+				  unsigned long *state)
+{
+	struct gpio_fan_data *fan_data = cdev->devdata;
+
+	if (!fan_data)
+		return -EINVAL;
+
+	*state = fan_data->num_speed - 1;
+	return 0;
+}
+
+static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev,
+				  unsigned long *state)
+{
+	struct gpio_fan_data *fan_data = cdev->devdata;
+
+	if (!fan_data)
+		return -EINVAL;
+
+	*state = fan_data->speed_index;
+	return 0;
+}
+
+static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev,
+				  unsigned long state)
+{
+	struct gpio_fan_data *fan_data = cdev->devdata;
+
+	if (!fan_data)
+		return -EINVAL;
+
+	set_fan_speed(fan_data, state);
+	return 0;
+}
+
+static const struct thermal_cooling_device_ops gpio_fan_cool_ops = {
+	.get_max_state = gpio_fan_get_max_state,
+	.get_cur_state = gpio_fan_get_cur_state,
+	.set_cur_state = gpio_fan_set_cur_state,
+};
+
+#ifdef CONFIG_OF_GPIO
+/*
+ * Translate OpenFirmware node properties into platform_data
+ */
+static int gpio_fan_get_of_pdata(struct device *dev,
+			    struct gpio_fan_platform_data *pdata)
+{
+	struct device_node *node;
+	struct gpio_fan_speed *speed;
+	unsigned *ctrl;
+	unsigned i;
+	u32 u;
+	struct property *prop;
+	const __be32 *p;
+
+	node = dev->of_node;
+
+	/* Alarm GPIO if one exists */
+	if (of_gpio_named_count(node, "alarm-gpios") > 0) {
+		struct gpio_fan_alarm *alarm;
+		int val;
+		enum of_gpio_flags flags;
+
+		alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
+					GFP_KERNEL);
+		if (!alarm)
+			return -ENOMEM;
+
+		val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
+		if (val < 0)
+			return val;
+		alarm->gpio = val;
+		alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+		pdata->alarm = alarm;
+	}
+
+	/* Fill GPIO pin array */
+	pdata->num_ctrl = of_gpio_count(node);
+	if (pdata->num_ctrl <= 0) {
+		if (pdata->alarm)
+			return 0;
+		dev_err(dev, "DT properties empty / missing");
+		return -ENODEV;
+	}
+	ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
+				GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+	for (i = 0; i < pdata->num_ctrl; i++) {
+		int val;
+
+		val = of_get_gpio(node, i);
+		if (val < 0)
+			return val;
+		ctrl[i] = val;
+	}
+	pdata->ctrl = ctrl;
+
+	/* Get number of RPM/ctrl_val pairs in speed map */
+	prop = of_find_property(node, "gpio-fan,speed-map", &i);
+	if (!prop) {
+		dev_err(dev, "gpio-fan,speed-map DT property missing");
+		return -ENODEV;
+	}
+	i = i / sizeof(u32);
+	if (i == 0 || i & 1) {
+		dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries");
+		return -ENODEV;
+	}
+	pdata->num_speed = i / 2;
+
+	/*
+	 * Populate speed map
+	 * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...>
+	 * this needs splitting into pairs to create gpio_fan_speed structs
+	 */
+	speed = devm_kzalloc(dev,
+			pdata->num_speed * sizeof(struct gpio_fan_speed),
+			GFP_KERNEL);
+	if (!speed)
+		return -ENOMEM;
+	p = NULL;
+	for (i = 0; i < pdata->num_speed; i++) {
+		p = of_prop_next_u32(prop, p, &u);
+		if (!p)
+			return -ENODEV;
+		speed[i].rpm = u;
+		p = of_prop_next_u32(prop, p, &u);
+		if (!p)
+			return -ENODEV;
+		speed[i].ctrl_val = u;
+	}
+	pdata->speed = speed;
+
+	return 0;
+}
+
+static const struct of_device_id of_gpio_fan_match[] = {
+	{ .compatible = "gpio-fan", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
+#endif /* CONFIG_OF_GPIO */
+
+static int gpio_fan_probe(struct platform_device *pdev)
+{
+	int err;
+	struct gpio_fan_data *fan_data;
+	struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
+				GFP_KERNEL);
+	if (!fan_data)
+		return -ENOMEM;
+
+#ifdef CONFIG_OF_GPIO
+	if (!pdata) {
+		pdata = devm_kzalloc(&pdev->dev,
+					sizeof(struct gpio_fan_platform_data),
+					GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		err = gpio_fan_get_of_pdata(&pdev->dev, pdata);
+		if (err)
+			return err;
+	}
+#else /* CONFIG_OF_GPIO */
+	if (!pdata)
+		return -EINVAL;
+#endif /* CONFIG_OF_GPIO */
+
+	fan_data->pdev = pdev;
+	platform_set_drvdata(pdev, fan_data);
+	mutex_init(&fan_data->lock);
+
+	/* Configure alarm GPIO if available. */
+	if (pdata->alarm) {
+		err = fan_alarm_init(fan_data, pdata->alarm);
+		if (err)
+			return err;
+	}
+
+	/* Configure control GPIOs if available. */
+	if (pdata->ctrl && pdata->num_ctrl > 0) {
+		if (!pdata->speed || pdata->num_speed <= 1)
+			return -EINVAL;
+		err = fan_ctrl_init(fan_data, pdata);
+		if (err)
+			return err;
+	}
+
+	/* Make this driver part of hwmon class. */
+	fan_data->hwmon_dev =
+		devm_hwmon_device_register_with_groups(&pdev->dev,
+						       "gpio_fan", fan_data,
+						       gpio_fan_groups);
+	if (IS_ERR(fan_data->hwmon_dev))
+		return PTR_ERR(fan_data->hwmon_dev);
+#ifdef CONFIG_OF_GPIO
+	/* Optional cooling device register for Device tree platforms */
+	fan_data->cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
+							    "gpio-fan",
+							    fan_data,
+							    &gpio_fan_cool_ops);
+#else /* CONFIG_OF_GPIO */
+	/* Optional cooling device register for non Device tree platforms */
+	fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data,
+							 &gpio_fan_cool_ops);
+#endif /* CONFIG_OF_GPIO */
+
+	dev_info(&pdev->dev, "GPIO fan initialized\n");
+
+	return 0;
+}
+
+static int gpio_fan_remove(struct platform_device *pdev)
+{
+	struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+	if (!IS_ERR(fan_data->cdev))
+		thermal_cooling_device_unregister(fan_data->cdev);
+
+	if (fan_data->ctrl)
+		set_fan_speed(fan_data, 0);
+
+	return 0;
+}
+
+static void gpio_fan_shutdown(struct platform_device *pdev)
+{
+	gpio_fan_remove(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int gpio_fan_suspend(struct device *dev)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	if (fan_data->ctrl) {
+		fan_data->resume_speed = fan_data->speed_index;
+		set_fan_speed(fan_data, 0);
+	}
+
+	return 0;
+}
+
+static int gpio_fan_resume(struct device *dev)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	if (fan_data->ctrl)
+		set_fan_speed(fan_data, fan_data->resume_speed);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
+#define GPIO_FAN_PM	(&gpio_fan_pm)
+#else
+#define GPIO_FAN_PM	NULL
+#endif
+
+static struct platform_driver gpio_fan_driver = {
+	.probe		= gpio_fan_probe,
+	.remove		= gpio_fan_remove,
+	.shutdown	= gpio_fan_shutdown,
+	.driver	= {
+		.name	= "gpio-fan",
+		.pm	= GPIO_FAN_PM,
+#ifdef CONFIG_OF_GPIO
+		.of_match_table = of_match_ptr(of_gpio_fan_match),
+#endif
+	},
+};
+
+module_platform_driver(gpio_fan_driver);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("GPIO FAN driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-fan");
diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c
new file mode 100644
index 0000000..7b73d20
--- /dev/null
+++ b/drivers/hwmon/hih6130.c
@@ -0,0 +1,267 @@
+/* Honeywell HIH-6130/HIH-6131 humidity and temperature sensor driver
+ *
+ * Copyright (C) 2012 Iain Paton <ipaton0@gmail.com>
+ *
+ * heavily based on the sht21 driver
+ * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
+ *
+ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Data sheets available (2012-06-22) at
+ * http://sensing.honeywell.com/index.php?ci_id=3106&la_id=1&defId=44872
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+/**
+ * struct hih6130 - HIH-6130 device specific data
+ * @hwmon_dev: device registered with hwmon
+ * @lock: mutex to protect measurement values
+ * @valid: only false before first measurement is taken
+ * @last_update: time of last update (jiffies)
+ * @temperature: cached temperature measurement value
+ * @humidity: cached humidity measurement value
+ * @write_length: length for I2C measurement request
+ */
+struct hih6130 {
+	struct i2c_client *client;
+	struct mutex lock;
+	bool valid;
+	unsigned long last_update;
+	int temperature;
+	int humidity;
+	size_t write_length;
+};
+
+/**
+ * hih6130_temp_ticks_to_millicelsius() - convert raw temperature ticks to
+ * milli celsius
+ * @ticks: temperature ticks value received from sensor
+ */
+static inline int hih6130_temp_ticks_to_millicelsius(int ticks)
+{
+	ticks = ticks >> 2;
+	/*
+	 * from data sheet section 5.0
+	 * Formula T = ( ticks / ( 2^14 - 2 ) ) * 165 -40
+	 */
+	return (DIV_ROUND_CLOSEST(ticks * 1650, 16382) - 400) * 100;
+}
+
+/**
+ * hih6130_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
+ * one-thousandths of a percent relative humidity
+ * @ticks: humidity ticks value received from sensor
+ */
+static inline int hih6130_rh_ticks_to_per_cent_mille(int ticks)
+{
+	ticks &= ~0xC000; /* clear status bits */
+	/*
+	 * from data sheet section 4.0
+	 * Formula RH = ( ticks / ( 2^14 -2 ) ) * 100
+	 */
+	return DIV_ROUND_CLOSEST(ticks * 1000, 16382) * 100;
+}
+
+/**
+ * hih6130_update_measurements() - get updated measurements from device
+ * @dev: device
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int hih6130_update_measurements(struct device *dev)
+{
+	struct hih6130 *hih6130 = dev_get_drvdata(dev);
+	struct i2c_client *client = hih6130->client;
+	int ret = 0;
+	int t;
+	unsigned char tmp[4];
+	struct i2c_msg msgs[1] = {
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = 4,
+			.buf = tmp,
+		}
+	};
+
+	mutex_lock(&hih6130->lock);
+
+	/*
+	 * While the measurement can be completed in ~40ms the sensor takes
+	 * much longer to react to a change in external conditions. How quickly
+	 * it reacts depends on airflow and other factors outwith our control.
+	 * The datasheet specifies maximum 'Response time' for humidity at 8s
+	 * and temperature at 30s under specified conditions.
+	 * We therefore choose to only read the sensor at most once per second.
+	 * This trades off pointless activity polling the sensor much faster
+	 * than it can react against better response times in conditions more
+	 * favourable than specified in the datasheet.
+	 */
+	if (time_after(jiffies, hih6130->last_update + HZ) || !hih6130->valid) {
+
+		/*
+		 * Write to slave address to request a measurement.
+		 * According with the datasheet it should be with no data, but
+		 * for systems with I2C bus drivers that do not allow zero
+		 * length packets we write one dummy byte to allow sensor
+		 * measurements on them.
+		 */
+		tmp[0] = 0;
+		ret = i2c_master_send(client, tmp, hih6130->write_length);
+		if (ret < 0)
+			goto out;
+
+		/* measurement cycle time is ~36.65msec */
+		msleep(40);
+
+		ret = i2c_transfer(client->adapter, msgs, 1);
+		if (ret < 0)
+			goto out;
+
+		if ((tmp[0] & 0xC0) != 0) {
+			dev_err(&client->dev, "Error while reading measurement result\n");
+			ret = -EIO;
+			goto out;
+		}
+
+		t = (tmp[0] << 8) + tmp[1];
+		hih6130->humidity = hih6130_rh_ticks_to_per_cent_mille(t);
+
+		t = (tmp[2] << 8) + tmp[3];
+		hih6130->temperature = hih6130_temp_ticks_to_millicelsius(t);
+
+		hih6130->last_update = jiffies;
+		hih6130->valid = true;
+	}
+out:
+	mutex_unlock(&hih6130->lock);
+
+	return ret >= 0 ? 0 : ret;
+}
+
+/**
+ * hih6130_show_temperature() - show temperature measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) 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 hih6130_show_temperature(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct hih6130 *hih6130 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = hih6130_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", hih6130->temperature);
+}
+
+/**
+ * hih6130_show_humidity() - show humidity measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) 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 hih6130_show_humidity(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct hih6130 *hih6130 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = hih6130_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", hih6130->humidity);
+}
+
+/* sysfs attributes */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, hih6130_show_temperature,
+	NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, hih6130_show_humidity,
+	NULL, 0);
+
+static struct attribute *hih6130_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(hih6130);
+
+static int hih6130_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct hih6130 *hih6130;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "adapter does not support true I2C\n");
+		return -ENODEV;
+	}
+
+	hih6130 = devm_kzalloc(dev, sizeof(*hih6130), GFP_KERNEL);
+	if (!hih6130)
+		return -ENOMEM;
+
+	hih6130->client = client;
+	mutex_init(&hih6130->lock);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_QUICK))
+		hih6130->write_length = 1;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   hih6130,
+							   hih6130_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* Device ID table */
+static const struct i2c_device_id hih6130_id[] = {
+	{ "hih6130", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, hih6130_id);
+
+static struct i2c_driver hih6130_driver = {
+	.driver.name = "hih6130",
+	.probe       = hih6130_probe,
+	.id_table    = hih6130_id,
+};
+
+module_i2c_driver(hih6130_driver);
+
+MODULE_AUTHOR("Iain Paton <ipaton0@gmail.com>");
+MODULE_DESCRIPTION("Honeywell HIH-6130 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c
new file mode 100644
index 0000000..4c3bbb7
--- /dev/null
+++ b/drivers/hwmon/htu21.c
@@ -0,0 +1,174 @@
+/*
+ * Measurement Specialties HTU21D humidity and temperature sensor driver
+ *
+ * Copyright (C) 2013 William Markezana <william.markezana@meas-spec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+
+/* HTU21 Commands */
+#define HTU21_T_MEASUREMENT_HM	0xE3
+#define HTU21_RH_MEASUREMENT_HM	0xE5
+
+struct htu21 {
+	struct i2c_client *client;
+	struct mutex lock;
+	bool valid;
+	unsigned long last_update;
+	int temperature;
+	int humidity;
+};
+
+static inline int htu21_temp_ticks_to_millicelsius(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((21965 * ticks) >> 13) - 46850;
+}
+
+static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((15625 * ticks) >> 13) - 6000;
+}
+
+static int htu21_update_measurements(struct device *dev)
+{
+	struct htu21 *htu21 = dev_get_drvdata(dev);
+	struct i2c_client *client = htu21->client;
+	int ret = 0;
+
+	mutex_lock(&htu21->lock);
+
+	if (time_after(jiffies, htu21->last_update + HZ / 2) ||
+	    !htu21->valid) {
+		ret = i2c_smbus_read_word_swapped(client,
+						  HTU21_T_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
+		ret = i2c_smbus_read_word_swapped(client,
+						  HTU21_RH_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
+		htu21->last_update = jiffies;
+		htu21->valid = true;
+	}
+out:
+	mutex_unlock(&htu21->lock);
+
+	return ret >= 0 ? 0 : ret;
+}
+
+static ssize_t htu21_show_temperature(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct htu21 *htu21 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = htu21_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", htu21->temperature);
+}
+
+static ssize_t htu21_show_humidity(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct htu21 *htu21 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = htu21_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", htu21->humidity);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+			  htu21_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
+			  htu21_show_humidity, NULL, 0);
+
+static struct attribute *htu21_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(htu21);
+
+static int htu21_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct htu21 *htu21;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+		dev_err(&client->dev,
+			"adapter does not support SMBus word transactions\n");
+		return -ENODEV;
+	}
+
+	htu21 = devm_kzalloc(dev, sizeof(*htu21), GFP_KERNEL);
+	if (!htu21)
+		return -ENOMEM;
+
+	htu21->client = client;
+	mutex_init(&htu21->lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   htu21,
+							   htu21_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id htu21_id[] = {
+	{ "htu21", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, htu21_id);
+
+static struct i2c_driver htu21_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "htu21",
+	},
+	.probe       = htu21_probe,
+	.id_table    = htu21_id,
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_DESCRIPTION("MEAS HTU21D humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
new file mode 100644
index 0000000..ef91b8a
--- /dev/null
+++ b/drivers/hwmon/hwmon-vid.c
@@ -0,0 +1,317 @@
+/*
+ * hwmon-vid.c - VID/VRM/VRD voltage conversions
+ *
+ * Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Partly imported from i2c-vid.h of the lm_sensors project
+ * Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * With assistance from Trent Piepho <xyzzy@speakeasy.org>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon-vid.h>
+
+/*
+ * Common code for decoding VID pins.
+ *
+ * References:
+ *
+ * For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
+ * available at http://developer.intel.com/.
+ *
+ * For VRD 10.0 and up, "VRD x.y Design Guide",
+ * available at http://developer.intel.com/.
+ *
+ * AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094,
+ * http://support.amd.com/us/Processor_TechDocs/26094.PDF
+ * Table 74. VID Code Voltages
+ * This corresponds to an arbitrary VRM code of 24 in the functions below.
+ * These CPU models (K8 revision <= E) have 5 VID pins. See also:
+ * Revision Guide for AMD Athlon 64 and AMD Opteron Processors, AMD Publication 25759,
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf
+ *
+ * AMD NPT Family 0Fh Processors, AMD Publication 32559,
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
+ * Table 71. VID Code Voltages
+ * This corresponds to an arbitrary VRM code of 25 in the functions below.
+ * These CPU models (K8 revision >= F) have 6 VID pins. See also:
+ * Revision Guide for AMD NPT Family 0Fh Processors, AMD Publication 33610,
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf
+ *
+ * The 17 specification is in fact Intel Mobile Voltage Positioning -
+ * (IMVP-II). You can find more information in the datasheet of Max1718
+ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
+ *
+ * The 13 specification corresponds to the Intel Pentium M series. There
+ * doesn't seem to be any named specification for these. The conversion
+ * tables are detailed directly in the various Pentium M datasheets:
+ * http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
+ *
+ * The 14 specification corresponds to Intel Core series. There
+ * doesn't seem to be any named specification for these. The conversion
+ * tables are detailed directly in the various Pentium Core datasheets:
+ * http://www.intel.com/design/mobile/datashts/309221.htm
+ *
+ * The 110 (VRM 11) specification corresponds to Intel Conroe based series.
+ * http://www.intel.com/design/processor/applnots/313214.htm
+ */
+
+/*
+ * vrm is the VRM/VRD document version multiplied by 10.
+ * val is the 4-bit or more VID code.
+ * Returned value is in mV to avoid floating point in the kernel.
+ * Some VID have some bits in uV scale, this is rounded to mV.
+ */
+int vid_from_reg(int val, u8 vrm)
+{
+	int vid;
+
+	switch (vrm) {
+
+	case 100:		/* VRD 10.0 */
+		/* compute in uV, round to mV */
+		val &= 0x3f;
+		if ((val & 0x1f) == 0x1f)
+			return 0;
+		if ((val & 0x1f) <= 0x09 || val == 0x0a)
+			vid = 1087500 - (val & 0x1f) * 25000;
+		else
+			vid = 1862500 - (val & 0x1f) * 25000;
+		if (val & 0x20)
+			vid -= 12500;
+		return (vid + 500) / 1000;
+
+	case 110:		/* Intel Conroe */
+				/* compute in uV, round to mV */
+		val &= 0xff;
+		if (val < 0x02 || val > 0xb2)
+			return 0;
+		return (1600000 - (val - 2) * 6250 + 500) / 1000;
+
+	case 24:		/* Athlon64 & Opteron */
+		val &= 0x1f;
+		if (val == 0x1f)
+			return 0;
+				/* fall through */
+	case 25:		/* AMD NPT 0Fh */
+		val &= 0x3f;
+		return (val < 32) ? 1550 - 25 * val
+			: 775 - (25 * (val - 31)) / 2;
+
+	case 26:		/* AMD family 10h to 15h, serial VID */
+		val &= 0x7f;
+		if (val >= 0x7c)
+			return 0;
+		return DIV_ROUND_CLOSEST(15500 - 125 * val, 10);
+
+	case 91:		/* VRM 9.1 */
+	case 90:		/* VRM 9.0 */
+		val &= 0x1f;
+		return val == 0x1f ? 0 :
+				     1850 - val * 25;
+
+	case 85:		/* VRM 8.5 */
+		val &= 0x1f;
+		return (val & 0x10  ? 25 : 0) +
+		       ((val & 0x0f) > 0x04 ? 2050 : 1250) -
+		       ((val & 0x0f) * 50);
+
+	case 84:		/* VRM 8.4 */
+		val &= 0x0f;
+				/* fall through */
+	case 82:		/* VRM 8.2 */
+		val &= 0x1f;
+		return val == 0x1f ? 0 :
+		       val & 0x10  ? 5100 - (val) * 100 :
+				     2050 - (val) * 50;
+	case 17:		/* Intel IMVP-II */
+		val &= 0x1f;
+		return val & 0x10 ? 975 - (val & 0xF) * 25 :
+				    1750 - val * 50;
+	case 13:
+	case 131:
+		val &= 0x3f;
+		/* Exception for Eden ULV 500 MHz */
+		if (vrm == 131 && val == 0x3f)
+			val++;
+		return 1708 - val * 16;
+	case 14:		/* Intel Core */
+				/* compute in uV, round to mV */
+		val &= 0x7f;
+		return val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000;
+	default:		/* report 0 for unknown */
+		if (vrm)
+			pr_warn("Requested unsupported VRM version (%u)\n",
+				(unsigned int)vrm);
+		return 0;
+	}
+}
+EXPORT_SYMBOL(vid_from_reg);
+
+/*
+ * After this point is the code to automatically determine which
+ * VRM/VRD specification should be used depending on the CPU.
+ */
+
+struct vrm_model {
+	u8 vendor;
+	u8 family;
+	u8 model_from;
+	u8 model_to;
+	u8 stepping_to;
+	u8 vrm_type;
+};
+
+#define ANY 0xFF
+
+#ifdef CONFIG_X86
+
+/*
+ * The stepping_to parameter is highest acceptable stepping for current line.
+ * The model match must be exact for 4-bit values. For model values 0x10
+ * and above (extended model), all models below the parameter will match.
+ */
+
+static struct vrm_model vrm_models[] = {
+	{X86_VENDOR_AMD, 0x6, 0x0, ANY, ANY, 90},	/* Athlon Duron etc */
+	{X86_VENDOR_AMD, 0xF, 0x0, 0x3F, ANY, 24},	/* Athlon 64, Opteron */
+	/*
+	 * In theory, all NPT family 0Fh processors have 6 VID pins and should
+	 * thus use vrm 25, however in practice not all mainboards route the
+	 * 6th VID pin because it is never needed. So we use the 5 VID pin
+	 * variant (vrm 24) for the models which exist today.
+	 */
+	{X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24},	/* NPT family 0Fh */
+	{X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25},	/* future fam. 0Fh */
+	{X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25},	/* NPT family 10h */
+	{X86_VENDOR_AMD, 0x11, 0x0, ANY, ANY, 26},	/* family 11h */
+	{X86_VENDOR_AMD, 0x12, 0x0, ANY, ANY, 26},	/* family 12h */
+	{X86_VENDOR_AMD, 0x14, 0x0, ANY, ANY, 26},	/* family 14h */
+	{X86_VENDOR_AMD, 0x15, 0x0, ANY, ANY, 26},	/* family 15h */
+
+	{X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82},	/* Pentium Pro,
+							 * Pentium II, Xeon,
+							 * Mobile Pentium,
+							 * Celeron */
+	{X86_VENDOR_INTEL, 0x6, 0x7, 0x7, ANY, 84},	/* Pentium III, Xeon */
+	{X86_VENDOR_INTEL, 0x6, 0x8, 0x8, ANY, 82},	/* Pentium III, Xeon */
+	{X86_VENDOR_INTEL, 0x6, 0x9, 0x9, ANY, 13},	/* Pentium M (130 nm) */
+	{X86_VENDOR_INTEL, 0x6, 0xA, 0xA, ANY, 82},	/* Pentium III Xeon */
+	{X86_VENDOR_INTEL, 0x6, 0xB, 0xB, ANY, 85},	/* Tualatin */
+	{X86_VENDOR_INTEL, 0x6, 0xD, 0xD, ANY, 13},	/* Pentium M (90 nm) */
+	{X86_VENDOR_INTEL, 0x6, 0xE, 0xE, ANY, 14},	/* Intel Core (65 nm) */
+	{X86_VENDOR_INTEL, 0x6, 0xF, ANY, ANY, 110},	/* Intel Conroe and
+							 * later */
+	{X86_VENDOR_INTEL, 0xF, 0x0, 0x0, ANY, 90},	/* P4 */
+	{X86_VENDOR_INTEL, 0xF, 0x1, 0x1, ANY, 90},	/* P4 Willamette */
+	{X86_VENDOR_INTEL, 0xF, 0x2, 0x2, ANY, 90},	/* P4 Northwood */
+	{X86_VENDOR_INTEL, 0xF, 0x3, ANY, ANY, 100},	/* Prescott and above
+							 * assume VRD 10 */
+
+	{X86_VENDOR_CENTAUR, 0x6, 0x7, 0x7, ANY, 85},	/* Eden ESP/Ezra */
+	{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x8, 0x7, 85},	/* Ezra T */
+	{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, 0x7, 85},	/* Nehemiah */
+	{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, ANY, 17},	/* C3-M, Eden-N */
+	{X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, 0x7, 0},	/* No information */
+	{X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, ANY, 13},	/* C7-M, C7,
+							 * Eden (Esther) */
+	{X86_VENDOR_CENTAUR, 0x6, 0xD, 0xD, ANY, 134},	/* C7-D, C7-M, C7,
+							 * Eden (Esther) */
+};
+
+/*
+ * Special case for VIA model D: there are two different possible
+ * VID tables, so we have to figure out first, which one must be
+ * used. This resolves temporary drm value 134 to 14 (Intel Core
+ * 7-bit VID), 13 (Pentium M 6-bit VID) or 131 (Pentium M 6-bit VID
+ * + quirk for Eden ULV 500 MHz).
+ * Note: something similar might be needed for model A, I'm not sure.
+ */
+static u8 get_via_model_d_vrm(void)
+{
+	unsigned int vid, brand, __maybe_unused dummy;
+	static const char *brands[4] = {
+		"C7-M", "C7", "Eden", "C7-D"
+	};
+
+	rdmsr(0x198, dummy, vid);
+	vid &= 0xff;
+
+	rdmsr(0x1154, brand, dummy);
+	brand = ((brand >> 4) ^ (brand >> 2)) & 0x03;
+
+	if (vid > 0x3f) {
+		pr_info("Using %d-bit VID table for VIA %s CPU\n",
+			7, brands[brand]);
+		return 14;
+	} else {
+		pr_info("Using %d-bit VID table for VIA %s CPU\n",
+			6, brands[brand]);
+		/* Enable quirk for Eden */
+		return brand == 2 ? 131 : 13;
+	}
+}
+
+static u8 find_vrm(u8 family, u8 model, u8 stepping, u8 vendor)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vrm_models); i++) {
+		if (vendor == vrm_models[i].vendor &&
+		    family == vrm_models[i].family &&
+		    model >= vrm_models[i].model_from &&
+		    model <= vrm_models[i].model_to &&
+		    stepping <= vrm_models[i].stepping_to)
+			return vrm_models[i].vrm_type;
+	}
+
+	return 0;
+}
+
+u8 vid_which_vrm(void)
+{
+	struct cpuinfo_x86 *c = &cpu_data(0);
+	u8 vrm_ret;
+
+	if (c->x86 < 6)		/* Any CPU with family lower than 6 */
+		return 0;	/* doesn't have VID */
+
+	vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor);
+	if (vrm_ret == 134)
+		vrm_ret = get_via_model_d_vrm();
+	if (vrm_ret == 0)
+		pr_info("Unknown VRM version of your x86 CPU\n");
+	return vrm_ret;
+}
+
+/* and now for something completely different for the non-x86 world */
+#else
+u8 vid_which_vrm(void)
+{
+	pr_info("Unknown VRM version of your CPU\n");
+	return 0;
+}
+#endif
+EXPORT_SYMBOL(vid_which_vrm);
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
+
+MODULE_DESCRIPTION("hwmon-vid driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
new file mode 100644
index 0000000..a26c385
--- /dev/null
+++ b/drivers/hwmon/hwmon.c
@@ -0,0 +1,287 @@
+/*
+ * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
+ *
+ * This file defines the sysfs class "hwmon", for use by sensors drivers.
+ *
+ * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/hwmon.h>
+#include <linux/gfp.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#define HWMON_ID_PREFIX "hwmon"
+#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
+
+struct hwmon_device {
+	const char *name;
+	struct device dev;
+};
+#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_hwmon_device(dev)->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *hwmon_dev_attrs[] = {
+	&dev_attr_name.attr,
+	NULL
+};
+
+static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
+					 struct attribute *attr, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+
+	if (to_hwmon_device(dev)->name == NULL)
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute_group hwmon_dev_attr_group = {
+	.attrs		= hwmon_dev_attrs,
+	.is_visible	= hwmon_dev_name_is_visible,
+};
+
+static const struct attribute_group *hwmon_dev_attr_groups[] = {
+	&hwmon_dev_attr_group,
+	NULL
+};
+
+static void hwmon_dev_release(struct device *dev)
+{
+	kfree(to_hwmon_device(dev));
+}
+
+static struct class hwmon_class = {
+	.name = "hwmon",
+	.owner = THIS_MODULE,
+	.dev_groups = hwmon_dev_attr_groups,
+	.dev_release = hwmon_dev_release,
+};
+
+static DEFINE_IDA(hwmon_ida);
+
+/**
+ * hwmon_device_register_with_groups - register w/ hwmon
+ * @dev: the parent device
+ * @name: hwmon name attribute
+ * @drvdata: driver data to attach to created device
+ * @groups: List of attribute groups to create
+ *
+ * hwmon_device_unregister() must be called when the device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new device.
+ */
+struct device *
+hwmon_device_register_with_groups(struct device *dev, const char *name,
+				  void *drvdata,
+				  const struct attribute_group **groups)
+{
+	struct hwmon_device *hwdev;
+	int err, id;
+
+	/* Do not accept invalid characters in hwmon name attribute */
+	if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
+		return ERR_PTR(-EINVAL);
+
+	id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
+	if (id < 0)
+		return ERR_PTR(id);
+
+	hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL);
+	if (hwdev == NULL) {
+		err = -ENOMEM;
+		goto ida_remove;
+	}
+
+	hwdev->name = name;
+	hwdev->dev.class = &hwmon_class;
+	hwdev->dev.parent = dev;
+	hwdev->dev.groups = groups;
+	hwdev->dev.of_node = dev ? dev->of_node : NULL;
+	dev_set_drvdata(&hwdev->dev, drvdata);
+	dev_set_name(&hwdev->dev, HWMON_ID_FORMAT, id);
+	err = device_register(&hwdev->dev);
+	if (err)
+		goto free;
+
+	return &hwdev->dev;
+
+free:
+	kfree(hwdev);
+ida_remove:
+	ida_simple_remove(&hwmon_ida, id);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups);
+
+/**
+ * hwmon_device_register - register w/ hwmon
+ * @dev: the device to register
+ *
+ * hwmon_device_unregister() must be called when the device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new device.
+ */
+struct device *hwmon_device_register(struct device *dev)
+{
+	return hwmon_device_register_with_groups(dev, NULL, NULL, NULL);
+}
+EXPORT_SYMBOL_GPL(hwmon_device_register);
+
+/**
+ * hwmon_device_unregister - removes the previously registered class device
+ *
+ * @dev: the class device to destroy
+ */
+void hwmon_device_unregister(struct device *dev)
+{
+	int id;
+
+	if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) {
+		device_unregister(dev);
+		ida_simple_remove(&hwmon_ida, id);
+	} else
+		dev_dbg(dev->parent,
+			"hwmon_device_unregister() failed: bad class ID!\n");
+}
+EXPORT_SYMBOL_GPL(hwmon_device_unregister);
+
+static void devm_hwmon_release(struct device *dev, void *res)
+{
+	struct device *hwdev = *(struct device **)res;
+
+	hwmon_device_unregister(hwdev);
+}
+
+/**
+ * devm_hwmon_device_register_with_groups - register w/ hwmon
+ * @dev: the parent device
+ * @name: hwmon name attribute
+ * @drvdata: driver data to attach to created device
+ * @groups: List of attribute groups to create
+ *
+ * Returns the pointer to the new device. The new device is automatically
+ * unregistered with the parent device.
+ */
+struct device *
+devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
+				       void *drvdata,
+				       const struct attribute_group **groups)
+{
+	struct device **ptr, *hwdev;
+
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups);
+	if (IS_ERR(hwdev))
+		goto error;
+
+	*ptr = hwdev;
+	devres_add(dev, ptr);
+	return hwdev;
+
+error:
+	devres_free(ptr);
+	return hwdev;
+}
+EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups);
+
+static int devm_hwmon_match(struct device *dev, void *res, void *data)
+{
+	struct device **hwdev = res;
+
+	return *hwdev == data;
+}
+
+/**
+ * devm_hwmon_device_unregister - removes a previously registered hwmon device
+ *
+ * @dev: the parent device of the device to unregister
+ */
+void devm_hwmon_device_unregister(struct device *dev)
+{
+	WARN_ON(devres_release(dev, devm_hwmon_release, devm_hwmon_match, dev));
+}
+EXPORT_SYMBOL_GPL(devm_hwmon_device_unregister);
+
+static void __init hwmon_pci_quirks(void)
+{
+#if defined CONFIG_X86 && defined CONFIG_PCI
+	struct pci_dev *sb;
+	u16 base;
+	u8 enable;
+
+	/* Open access to 0x295-0x296 on MSI MS-7031 */
+	sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
+	if (sb) {
+		if (sb->subsystem_vendor == 0x1462 &&	/* MSI */
+		    sb->subsystem_device == 0x0031) {	/* MS-7031 */
+			pci_read_config_byte(sb, 0x48, &enable);
+			pci_read_config_word(sb, 0x64, &base);
+
+			if (base == 0 && !(enable & BIT(2))) {
+				dev_info(&sb->dev,
+					 "Opening wide generic port at 0x295\n");
+				pci_write_config_word(sb, 0x64, 0x295);
+				pci_write_config_byte(sb, 0x48,
+						      enable | BIT(2));
+			}
+		}
+		pci_dev_put(sb);
+	}
+#endif
+}
+
+static int __init hwmon_init(void)
+{
+	int err;
+
+	hwmon_pci_quirks();
+
+	err = class_register(&hwmon_class);
+	if (err) {
+		pr_err("couldn't register hwmon sysfs class\n");
+		return err;
+	}
+	return 0;
+}
+
+static void __exit hwmon_exit(void)
+{
+	class_unregister(&hwmon_class);
+}
+
+subsys_initcall(hwmon_init);
+module_exit(hwmon_exit);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c
new file mode 100644
index 0000000..3e3ccbf
--- /dev/null
+++ b/drivers/hwmon/i5500_temp.c
@@ -0,0 +1,149 @@
+/*
+ * i5500_temp - Driver for Intel 5500/5520/X58 chipset thermal sensor
+ *
+ * Copyright (C) 2012, 2014 Jean Delvare <jdelvare@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Register definitions from datasheet */
+#define REG_TSTHRCATA	0xE2
+#define REG_TSCTRL	0xE8
+#define REG_TSTHRRPEX	0xEB
+#define REG_TSTHRLO	0xEC
+#define REG_TSTHRHI	0xEE
+#define REG_CTHINT	0xF0
+#define REG_TSFSC	0xF3
+#define REG_CTSTS	0xF4
+#define REG_TSTHRRQPI	0xF5
+#define REG_CTCTRL	0xF7
+#define REG_TSTIMER	0xF8
+
+/*
+ * Sysfs stuff
+ */
+
+/* Sensor resolution : 0.5 degree C */
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	long temp;
+	u16 tsthrhi;
+	s8 tsfsc;
+
+	pci_read_config_word(pdev, REG_TSTHRHI, &tsthrhi);
+	pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
+	temp = ((long)tsthrhi - tsfsc) * 500;
+
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_thresh(struct device *dev,
+			   struct device_attribute *devattr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	int reg = to_sensor_dev_attr(devattr)->index;
+	long temp;
+	u16 tsthr;
+
+	pci_read_config_word(pdev, reg, &tsthr);
+	temp = tsthr * 500;
+
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	int nr = to_sensor_dev_attr(devattr)->index;
+	u8 ctsts;
+
+	pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
+	return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_thresh, NULL, 0xE2);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_thresh, NULL, 0xEC);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_thresh, NULL, 0xEE);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
+
+static struct attribute *i5500_temp_attrs[] = {
+	&dev_attr_temp1_input.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(i5500_temp);
+
+static const struct pci_device_id i5500_temp_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) },
+	{ 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, i5500_temp_ids);
+
+static int i5500_temp_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *id)
+{
+	int err;
+	struct device *hwmon_dev;
+	u32 tstimer;
+	s8 tsfsc;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to enable device\n");
+		return err;
+	}
+
+	pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
+	pci_read_config_dword(pdev, REG_TSTIMER, &tstimer);
+	if (tsfsc == 0x7F && tstimer == 0x07D30D40) {
+		dev_notice(&pdev->dev, "Sensor seems to be disabled\n");
+		return -ENODEV;
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+							   "intel5500", NULL,
+							   i5500_temp_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct pci_driver i5500_temp_driver = {
+	.name = "i5500_temp",
+	.id_table = i5500_temp_ids,
+	.probe = i5500_temp_probe,
+};
+
+module_pci_driver(i5500_temp_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("Intel 5500/5520/X58 chipset thermal sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
new file mode 100644
index 0000000..6b3d197
--- /dev/null
+++ b/drivers/hwmon/i5k_amb.c
@@ -0,0 +1,616 @@
+/*
+ * A hwmon driver for the Intel 5000 series chipset FB-DIMM AMB
+ * temperature sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/log2.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define DRVNAME "i5k_amb"
+
+#define I5K_REG_AMB_BASE_ADDR		0x48
+#define I5K_REG_AMB_LEN_ADDR		0x50
+#define I5K_REG_CHAN0_PRESENCE_ADDR	0x64
+#define I5K_REG_CHAN1_PRESENCE_ADDR	0x66
+
+#define AMB_REG_TEMP_MIN_ADDR		0x80
+#define AMB_REG_TEMP_MID_ADDR		0x81
+#define AMB_REG_TEMP_MAX_ADDR		0x82
+#define AMB_REG_TEMP_STATUS_ADDR	0x84
+#define AMB_REG_TEMP_ADDR		0x85
+
+#define AMB_CONFIG_SIZE			2048
+#define AMB_FUNC_3_OFFSET		768
+
+static unsigned long amb_reg_temp_status(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_STATUS_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_min(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MIN_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_mid(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MID_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_max(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MAX_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+#define MAX_MEM_CHANNELS		4
+#define MAX_AMBS_PER_CHANNEL		16
+#define MAX_AMBS			(MAX_MEM_CHANNELS * \
+					 MAX_AMBS_PER_CHANNEL)
+#define CHANNEL_SHIFT			4
+#define DIMM_MASK			0xF
+/*
+ * Ugly hack: For some reason the highest bit is set if there
+ * are _any_ DIMMs in the channel.  Attempting to read from
+ * this "high-order" AMB results in a memory bus error, so
+ * for now we'll just ignore that top bit, even though that
+ * might prevent us from seeing the 16th DIMM in the channel.
+ */
+#define REAL_MAX_AMBS_PER_CHANNEL	15
+#define KNOBS_PER_AMB			6
+
+static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit)
+{
+	return byte_num * MAX_AMBS_PER_CHANNEL + bit;
+}
+
+#define AMB_SYSFS_NAME_LEN		16
+struct i5k_device_attribute {
+	struct sensor_device_attribute s_attr;
+	char name[AMB_SYSFS_NAME_LEN];
+};
+
+struct i5k_amb_data {
+	struct device *hwmon_dev;
+
+	unsigned long amb_base;
+	unsigned long amb_len;
+	u16 amb_present[MAX_MEM_CHANNELS];
+	void __iomem *amb_mmio;
+	struct i5k_device_attribute *attrs;
+	unsigned int num_attrs;
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	return sprintf(buf, "%s\n", DRVNAME);
+}
+
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct platform_device *amb_pdev;
+
+static u8 amb_read_byte(struct i5k_amb_data *data, unsigned long offset)
+{
+	return ioread8(data->amb_mmio + offset);
+}
+
+static void amb_write_byte(struct i5k_amb_data *data, unsigned long offset,
+			   u8 val)
+{
+	iowrite8(val, data->amb_mmio + offset);
+}
+
+static ssize_t show_amb_alarm(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+
+	if (!(amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x20) &&
+	     (amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x8))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_amb_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf,
+			     size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp;
+	int ret = kstrtoul(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	temp = temp / 500;
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_min(attr->index), temp);
+	return count;
+}
+
+static ssize_t store_amb_mid(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf,
+			     size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp;
+	int ret = kstrtoul(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	temp = temp / 500;
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_mid(attr->index), temp);
+	return count;
+}
+
+static ssize_t store_amb_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf,
+			     size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp;
+	int ret = kstrtoul(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	temp = temp / 500;
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_max(attr->index), temp);
+	return count;
+}
+
+static ssize_t show_amb_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_min(attr->index)));
+}
+
+static ssize_t show_amb_mid(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_mid(attr->index)));
+}
+
+static ssize_t show_amb_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_max(attr->index)));
+}
+
+static ssize_t show_amb_temp(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp(attr->index)));
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "Ch. %d DIMM %d\n", attr->index >> CHANNEL_SHIFT,
+		       attr->index & DIMM_MASK);
+}
+
+static int i5k_amb_hwmon_init(struct platform_device *pdev)
+{
+	int i, j, k, d = 0;
+	u16 c;
+	int res = 0;
+	int num_ambs = 0;
+	struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+	/* Count the number of AMBs found */
+	/* ignore the high-order bit, see "Ugly hack" comment above */
+	for (i = 0; i < MAX_MEM_CHANNELS; i++)
+		num_ambs += hweight16(data->amb_present[i] & 0x7fff);
+
+	/* Set up sysfs stuff */
+	data->attrs = kzalloc(sizeof(*data->attrs) * num_ambs * KNOBS_PER_AMB,
+				GFP_KERNEL);
+	if (!data->attrs)
+		return -ENOMEM;
+	data->num_attrs = 0;
+
+	for (i = 0; i < MAX_MEM_CHANNELS; i++) {
+		c = data->amb_present[i];
+		for (j = 0; j < REAL_MAX_AMBS_PER_CHANNEL; j++, c >>= 1) {
+			struct i5k_device_attribute *iattr;
+
+			k = amb_num_from_reg(i, j);
+			if (!(c & 0x1))
+				continue;
+			d++;
+
+			/* sysfs label */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_label", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_label;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_input", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_temp;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature min sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_min", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_min;
+			iattr->s_attr.dev_attr.store = store_amb_min;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature mid sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_mid", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_mid;
+			iattr->s_attr.dev_attr.store = store_amb_mid;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature max sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_max", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_max;
+			iattr->s_attr.dev_attr.store = store_amb_max;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature alarm sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_alarm", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_alarm;
+			iattr->s_attr.index = k;
+			sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+		}
+	}
+
+	res = device_create_file(&pdev->dev, &dev_attr_name);
+	if (res)
+		goto exit_remove;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		res = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return res;
+
+exit_remove:
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	for (i = 0; i < data->num_attrs; i++)
+		device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+	kfree(data->attrs);
+
+	return res;
+}
+
+static int i5k_amb_add(void)
+{
+	int res = -ENODEV;
+
+	/* only ever going to be one of these */
+	amb_pdev = platform_device_alloc(DRVNAME, 0);
+	if (!amb_pdev)
+		return -ENOMEM;
+
+	res = platform_device_add(amb_pdev);
+	if (res)
+		goto err;
+	return 0;
+
+err:
+	platform_device_put(amb_pdev);
+	return res;
+}
+
+static int i5k_find_amb_registers(struct i5k_amb_data *data,
+					    unsigned long devid)
+{
+	struct pci_dev *pcidev;
+	u32 val32;
+	int res = -ENODEV;
+
+	/* Find AMB register memory space */
+	pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				devid,
+				NULL);
+	if (!pcidev)
+		return -ENODEV;
+
+	if (pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32))
+		goto out;
+	data->amb_base = val32;
+
+	if (pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32))
+		goto out;
+	data->amb_len = val32;
+
+	/* Is it big enough? */
+	if (data->amb_len < AMB_CONFIG_SIZE * MAX_AMBS) {
+		dev_err(&pcidev->dev, "AMB region too small!\n");
+		goto out;
+	}
+
+	res = 0;
+out:
+	pci_dev_put(pcidev);
+	return res;
+}
+
+static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id)
+{
+	struct pci_dev *pcidev;
+	u16 val16;
+	int res = -ENODEV;
+
+	/* Copy the DIMM presence map for these two channels */
+	pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
+	if (!pcidev)
+		return -ENODEV;
+
+	if (pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16))
+		goto out;
+	amb_present[0] = val16;
+
+	if (pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16))
+		goto out;
+	amb_present[1] = val16;
+
+	res = 0;
+
+out:
+	pci_dev_put(pcidev);
+	return res;
+}
+
+static struct {
+	unsigned long err;
+	unsigned long fbd0;
+} chipset_ids[]  = {
+	{ PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 },
+	{ PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 },
+	{ 0, 0 }
+};
+
+#ifdef MODULE
+static struct pci_device_id i5k_amb_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+#endif
+
+static int i5k_amb_probe(struct platform_device *pdev)
+{
+	struct i5k_amb_data *data;
+	struct resource *reso;
+	int i, res;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* Figure out where the AMB registers live */
+	i = 0;
+	do {
+		res = i5k_find_amb_registers(data, chipset_ids[i].err);
+		if (res == 0)
+			break;
+		i++;
+	} while (chipset_ids[i].err);
+
+	if (res)
+		goto err;
+
+	/* Copy the DIMM presence map for the first two channels */
+	res = i5k_channel_probe(&data->amb_present[0], chipset_ids[i].fbd0);
+	if (res)
+		goto err;
+
+	/* Copy the DIMM presence map for the optional second two channels */
+	i5k_channel_probe(&data->amb_present[2], chipset_ids[i].fbd0 + 1);
+
+	/* Set up resource regions */
+	reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
+	if (!reso) {
+		res = -EBUSY;
+		goto err;
+	}
+
+	data->amb_mmio = ioremap_nocache(data->amb_base, data->amb_len);
+	if (!data->amb_mmio) {
+		res = -EBUSY;
+		goto err_map_failed;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	res = i5k_amb_hwmon_init(pdev);
+	if (res)
+		goto err_init_failed;
+
+	return res;
+
+err_init_failed:
+	iounmap(data->amb_mmio);
+err_map_failed:
+	release_mem_region(data->amb_base, data->amb_len);
+err:
+	kfree(data);
+	return res;
+}
+
+static int i5k_amb_remove(struct platform_device *pdev)
+{
+	int i;
+	struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	for (i = 0; i < data->num_attrs; i++)
+		device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+	kfree(data->attrs);
+	iounmap(data->amb_mmio);
+	release_mem_region(data->amb_base, data->amb_len);
+	kfree(data);
+	return 0;
+}
+
+static struct platform_driver i5k_amb_driver = {
+	.driver = {
+		.name = DRVNAME,
+	},
+	.probe = i5k_amb_probe,
+	.remove = i5k_amb_remove,
+};
+
+static int __init i5k_amb_init(void)
+{
+	int res;
+
+	res = platform_driver_register(&i5k_amb_driver);
+	if (res)
+		return res;
+
+	res = i5k_amb_add();
+	if (res)
+		platform_driver_unregister(&i5k_amb_driver);
+
+	return res;
+}
+
+static void __exit i5k_amb_exit(void)
+{
+	platform_device_unregister(amb_pdev);
+	platform_driver_unregister(&i5k_amb_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(i5k_amb_init);
+module_exit(i5k_amb_exit);
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
new file mode 100644
index 0000000..7a8a6fb
--- /dev/null
+++ b/drivers/hwmon/ibmaem.c
@@ -0,0 +1,1117 @@
+/*
+ * A hwmon driver for the IBM System Director Active Energy Manager (AEM)
+ * temperature/power/energy sensors and capping functionality.
+ * Copyright (C) 2008 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/kdev_t.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/math64.h>
+#include <linux/time.h>
+#include <linux/err.h>
+
+#define REFRESH_INTERVAL	(HZ)
+#define IPMI_TIMEOUT		(30 * HZ)
+#define DRVNAME			"aem"
+
+#define AEM_NETFN		0x2E
+
+#define AEM_FIND_FW_CMD		0x80
+#define AEM_ELEMENT_CMD		0x81
+#define AEM_FW_INSTANCE_CMD	0x82
+
+#define AEM_READ_ELEMENT_CFG	0x80
+#define AEM_READ_BUFFER		0x81
+#define AEM_READ_REGISTER	0x82
+#define AEM_WRITE_REGISTER	0x83
+#define AEM_SET_REG_MASK	0x84
+#define AEM_CLEAR_REG_MASK	0x85
+#define AEM_READ_ELEMENT_CFG2	0x86
+
+#define AEM_CONTROL_ELEMENT	0
+#define AEM_ENERGY_ELEMENT	1
+#define AEM_CLOCK_ELEMENT	4
+#define AEM_POWER_CAP_ELEMENT	7
+#define AEM_EXHAUST_ELEMENT	9
+#define AEM_POWER_ELEMENT	10
+
+#define AEM_MODULE_TYPE_ID	0x0001
+
+#define AEM2_NUM_ENERGY_REGS	2
+#define AEM2_NUM_PCAP_REGS	6
+#define AEM2_NUM_TEMP_REGS	2
+#define AEM2_NUM_SENSORS	14
+
+#define AEM1_NUM_ENERGY_REGS	1
+#define AEM1_NUM_SENSORS	3
+
+/* AEM 2.x has more energy registers */
+#define AEM_NUM_ENERGY_REGS	AEM2_NUM_ENERGY_REGS
+/* AEM 2.x needs more sensor files */
+#define AEM_NUM_SENSORS		AEM2_NUM_SENSORS
+
+#define POWER_CAP		0
+#define POWER_CAP_MAX_HOTPLUG	1
+#define POWER_CAP_MAX		2
+#define	POWER_CAP_MIN_WARNING	3
+#define POWER_CAP_MIN		4
+#define	POWER_AUX		5
+
+#define AEM_DEFAULT_POWER_INTERVAL 1000
+#define AEM_MIN_POWER_INTERVAL	200
+#define UJ_PER_MJ		1000L
+
+static DEFINE_IDA(aem_ida);
+
+static struct platform_driver aem_driver = {
+	.driver = {
+		.name = DRVNAME,
+		.bus = &platform_bus_type,
+	}
+};
+
+struct aem_ipmi_data {
+	struct completion	read_complete;
+	struct ipmi_addr	address;
+	ipmi_user_t		user;
+	int			interface;
+
+	struct kernel_ipmi_msg	tx_message;
+	long			tx_msgid;
+
+	void			*rx_msg_data;
+	unsigned short		rx_msg_len;
+	unsigned char		rx_result;
+	int			rx_recv_type;
+
+	struct device		*bmc_device;
+};
+
+struct aem_ro_sensor_template {
+	char *label;
+	ssize_t (*show)(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf);
+	int index;
+};
+
+struct aem_rw_sensor_template {
+	char *label;
+	ssize_t (*show)(struct device *dev,
+			struct device_attribute *devattr,
+			char *buf);
+	ssize_t (*set)(struct device *dev,
+		       struct device_attribute *devattr,
+		       const char *buf, size_t count);
+	int index;
+};
+
+struct aem_data {
+	struct list_head	list;
+
+	struct device		*hwmon_dev;
+	struct platform_device	*pdev;
+	struct mutex		lock;
+	char			valid;
+	unsigned long		last_updated;	/* In jiffies */
+	u8			ver_major;
+	u8			ver_minor;
+	u8			module_handle;
+	int			id;
+	struct aem_ipmi_data	ipmi;
+
+	/* Function and buffer to update sensors */
+	void (*update)(struct aem_data *data);
+	struct aem_read_sensor_resp *rs_resp;
+
+	/*
+	 * AEM 1.x sensors:
+	 * Available sensors:
+	 * Energy meter
+	 * Power meter
+	 *
+	 * AEM 2.x sensors:
+	 * Two energy meters
+	 * Two power meters
+	 * Two temperature sensors
+	 * Six power cap registers
+	 */
+
+	/* sysfs attrs */
+	struct sensor_device_attribute	sensors[AEM_NUM_SENSORS];
+
+	/* energy use in mJ */
+	u64			energy[AEM_NUM_ENERGY_REGS];
+
+	/* power sampling interval in ms */
+	unsigned long		power_period[AEM_NUM_ENERGY_REGS];
+
+	/* Everything past here is for AEM2 only */
+
+	/* power caps in dW */
+	u16			pcap[AEM2_NUM_PCAP_REGS];
+
+	/* exhaust temperature in C */
+	u8			temp[AEM2_NUM_TEMP_REGS];
+};
+
+/* Data structures returned by the AEM firmware */
+struct aem_iana_id {
+	u8			bytes[3];
+};
+static struct aem_iana_id system_x_id = {
+	.bytes = {0x4D, 0x4F, 0x00}
+};
+
+/* These are used to find AEM1 instances */
+struct aem_find_firmware_req {
+	struct aem_iana_id	id;
+	u8			rsvd;
+	__be16			index;
+	__be16			module_type_id;
+} __packed;
+
+struct aem_find_firmware_resp {
+	struct aem_iana_id	id;
+	u8			num_instances;
+} __packed;
+
+/* These are used to find AEM2 instances */
+struct aem_find_instance_req {
+	struct aem_iana_id	id;
+	u8			instance_number;
+	__be16			module_type_id;
+} __packed;
+
+struct aem_find_instance_resp {
+	struct aem_iana_id	id;
+	u8			num_instances;
+	u8			major;
+	u8			minor;
+	u8			module_handle;
+	u16			record_id;
+} __packed;
+
+/* These are used to query sensors */
+struct aem_read_sensor_req {
+	struct aem_iana_id	id;
+	u8			module_handle;
+	u8			element;
+	u8			subcommand;
+	u8			reg;
+	u8			rx_buf_size;
+} __packed;
+
+struct aem_read_sensor_resp {
+	struct aem_iana_id	id;
+	u8			bytes[0];
+} __packed;
+
+/* Data structures to talk to the IPMI layer */
+struct aem_driver_data {
+	struct list_head	aem_devices;
+	struct ipmi_smi_watcher	bmc_events;
+	struct ipmi_user_hndl	ipmi_hndlrs;
+};
+
+static void aem_register_bmc(int iface, struct device *dev);
+static void aem_bmc_gone(int iface);
+static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+
+static void aem_remove_sensors(struct aem_data *data);
+static int aem1_find_sensors(struct aem_data *data);
+static int aem2_find_sensors(struct aem_data *data);
+static void update_aem1_sensors(struct aem_data *data);
+static void update_aem2_sensors(struct aem_data *data);
+
+static struct aem_driver_data driver_data = {
+	.aem_devices = LIST_HEAD_INIT(driver_data.aem_devices),
+	.bmc_events = {
+		.owner = THIS_MODULE,
+		.new_smi = aem_register_bmc,
+		.smi_gone = aem_bmc_gone,
+	},
+	.ipmi_hndlrs = {
+		.ipmi_recv_hndl = aem_msg_handler,
+	},
+};
+
+/* Functions to talk to the IPMI layer */
+
+/* Initialize IPMI address, message buffers and user data */
+static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
+			      struct device *bmc)
+{
+	int err;
+
+	init_completion(&data->read_complete);
+	data->bmc_device = bmc;
+
+	/* Initialize IPMI address */
+	data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	data->address.channel = IPMI_BMC_CHANNEL;
+	data->address.data[0] = 0;
+	data->interface = iface;
+
+	/* Initialize message buffers */
+	data->tx_msgid = 0;
+	data->tx_message.netfn = AEM_NETFN;
+
+	/* Create IPMI messaging interface user */
+	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+			       data, &data->user);
+	if (err < 0) {
+		dev_err(bmc,
+			"Unable to register user with IPMI interface %d\n",
+			data->interface);
+		return err;
+	}
+
+	return 0;
+}
+
+/* Send an IPMI command */
+static int aem_send_message(struct aem_ipmi_data *data)
+{
+	int err;
+
+	err = ipmi_validate_addr(&data->address, sizeof(data->address));
+	if (err)
+		goto out;
+
+	data->tx_msgid++;
+	err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+				   &data->tx_message, data, 0, 0, 0);
+	if (err)
+		goto out1;
+
+	return 0;
+out1:
+	dev_err(data->bmc_device, "request_settime=%x\n", err);
+	return err;
+out:
+	dev_err(data->bmc_device, "validate_addr=%x\n", err);
+	return err;
+}
+
+/* Dispatch IPMI messages to callers */
+static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+	unsigned short rx_len;
+	struct aem_ipmi_data *data = user_msg_data;
+
+	if (msg->msgid != data->tx_msgid) {
+		dev_err(data->bmc_device,
+			"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
+			(int)msg->msgid,
+			(int)data->tx_msgid);
+		ipmi_free_recv_msg(msg);
+		return;
+	}
+
+	data->rx_recv_type = msg->recv_type;
+	if (msg->msg.data_len > 0)
+		data->rx_result = msg->msg.data[0];
+	else
+		data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+	if (msg->msg.data_len > 1) {
+		rx_len = msg->msg.data_len - 1;
+		if (data->rx_msg_len < rx_len)
+			rx_len = data->rx_msg_len;
+		data->rx_msg_len = rx_len;
+		memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+	} else
+		data->rx_msg_len = 0;
+
+	ipmi_free_recv_msg(msg);
+	complete(&data->read_complete);
+}
+
+/* Sensor support functions */
+
+/* Read a sensor value; must be called with data->lock held */
+static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
+			   void *buf, size_t size)
+{
+	int rs_size, res;
+	struct aem_read_sensor_req rs_req;
+	/* Use preallocated rx buffer */
+	struct aem_read_sensor_resp *rs_resp = data->rs_resp;
+	struct aem_ipmi_data *ipmi = &data->ipmi;
+
+	/* AEM registers are 1, 2, 4 or 8 bytes */
+	switch (size) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rs_req.id = system_x_id;
+	rs_req.module_handle = data->module_handle;
+	rs_req.element = elt;
+	rs_req.subcommand = AEM_READ_REGISTER;
+	rs_req.reg = reg;
+	rs_req.rx_buf_size = size;
+
+	ipmi->tx_message.cmd = AEM_ELEMENT_CMD;
+	ipmi->tx_message.data = (char *)&rs_req;
+	ipmi->tx_message.data_len = sizeof(rs_req);
+
+	rs_size = sizeof(*rs_resp) + size;
+	ipmi->rx_msg_data = rs_resp;
+	ipmi->rx_msg_len = rs_size;
+
+	aem_send_message(ipmi);
+
+	res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
+	if (!res) {
+		res = -ETIMEDOUT;
+		goto out;
+	}
+
+	if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
+	    memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) {
+		res = -ENOENT;
+		goto out;
+	}
+
+	switch (size) {
+	case 1: {
+		u8 *x = buf;
+		*x = rs_resp->bytes[0];
+		break;
+	}
+	case 2: {
+		u16 *x = buf;
+		*x = be16_to_cpup((__be16 *)rs_resp->bytes);
+		break;
+	}
+	case 4: {
+		u32 *x = buf;
+		*x = be32_to_cpup((__be32 *)rs_resp->bytes);
+		break;
+	}
+	case 8: {
+		u64 *x = buf;
+		*x = be64_to_cpup((__be64 *)rs_resp->bytes);
+		break;
+	}
+	}
+	res = 0;
+
+out:
+	return res;
+}
+
+/* Update AEM energy registers */
+static void update_aem_energy_one(struct aem_data *data, int which)
+{
+	aem_read_sensor(data, AEM_ENERGY_ELEMENT, which,
+			&data->energy[which], 8);
+}
+
+static void update_aem_energy(struct aem_data *data)
+{
+	update_aem_energy_one(data, 0);
+	if (data->ver_major < 2)
+		return;
+	update_aem_energy_one(data, 1);
+}
+
+/* Update all AEM1 sensors */
+static void update_aem1_sensors(struct aem_data *data)
+{
+	mutex_lock(&data->lock);
+	if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+	    data->valid)
+		goto out;
+
+	update_aem_energy(data);
+out:
+	mutex_unlock(&data->lock);
+}
+
+/* Update all AEM2 sensors */
+static void update_aem2_sensors(struct aem_data *data)
+{
+	int i;
+
+	mutex_lock(&data->lock);
+	if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+	    data->valid)
+		goto out;
+
+	update_aem_energy(data);
+	aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 0, &data->temp[0], 1);
+	aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 1, &data->temp[1], 1);
+
+	for (i = POWER_CAP; i <= POWER_AUX; i++)
+		aem_read_sensor(data, AEM_POWER_CAP_ELEMENT, i,
+				&data->pcap[i], 2);
+out:
+	mutex_unlock(&data->lock);
+}
+
+/* Delete an AEM instance */
+static void aem_delete(struct aem_data *data)
+{
+	list_del(&data->list);
+	aem_remove_sensors(data);
+	kfree(data->rs_resp);
+	hwmon_device_unregister(data->hwmon_dev);
+	ipmi_destroy_user(data->ipmi.user);
+	platform_set_drvdata(data->pdev, NULL);
+	platform_device_unregister(data->pdev);
+	ida_simple_remove(&aem_ida, data->id);
+	kfree(data);
+}
+
+/* Probe functions for AEM1 devices */
+
+/* Retrieve version and module handle for an AEM1 instance */
+static int aem_find_aem1_count(struct aem_ipmi_data *data)
+{
+	int res;
+	struct aem_find_firmware_req	ff_req;
+	struct aem_find_firmware_resp	ff_resp;
+
+	ff_req.id = system_x_id;
+	ff_req.index = 0;
+	ff_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID);
+
+	data->tx_message.cmd = AEM_FIND_FW_CMD;
+	data->tx_message.data = (char *)&ff_req;
+	data->tx_message.data_len = sizeof(ff_req);
+
+	data->rx_msg_data = &ff_resp;
+	data->rx_msg_len = sizeof(ff_resp);
+
+	aem_send_message(data);
+
+	res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT);
+	if (!res)
+		return -ETIMEDOUT;
+
+	if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) ||
+	    memcmp(&ff_resp.id, &system_x_id, sizeof(system_x_id)))
+		return -ENOENT;
+
+	return ff_resp.num_instances;
+}
+
+/* Find and initialize one AEM1 instance */
+static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
+{
+	struct aem_data *data;
+	int i;
+	int res = -ENOMEM;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return res;
+	mutex_init(&data->lock);
+
+	/* Copy instance data */
+	data->ver_major = 1;
+	data->ver_minor = 0;
+	data->module_handle = module_handle;
+	for (i = 0; i < AEM1_NUM_ENERGY_REGS; i++)
+		data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
+
+	/* Create sub-device for this fw instance */
+	data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL);
+	if (data->id < 0)
+		goto id_err;
+
+	data->pdev = platform_device_alloc(DRVNAME, data->id);
+	if (!data->pdev)
+		goto dev_err;
+	data->pdev->dev.driver = &aem_driver.driver;
+
+	res = platform_device_add(data->pdev);
+	if (res)
+		goto ipmi_err;
+
+	platform_set_drvdata(data->pdev, data);
+
+	/* Set up IPMI interface */
+	res = aem_init_ipmi_data(&data->ipmi, probe->interface,
+				 probe->bmc_device);
+	if (res)
+		goto ipmi_err;
+
+	/* Register with hwmon */
+	data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(&data->pdev->dev,
+			"Unable to register hwmon device for IPMI interface %d\n",
+			probe->interface);
+		res = PTR_ERR(data->hwmon_dev);
+		goto hwmon_reg_err;
+	}
+
+	data->update = update_aem1_sensors;
+	data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL);
+	if (!data->rs_resp) {
+		res = -ENOMEM;
+		goto alloc_resp_err;
+	}
+
+	/* Find sensors */
+	res = aem1_find_sensors(data);
+	if (res)
+		goto sensor_err;
+
+	/* Add to our list of AEM devices */
+	list_add_tail(&data->list, &driver_data.aem_devices);
+
+	dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n",
+		 data->ver_major, data->ver_minor,
+		 data->module_handle);
+	return 0;
+
+sensor_err:
+	kfree(data->rs_resp);
+alloc_resp_err:
+	hwmon_device_unregister(data->hwmon_dev);
+hwmon_reg_err:
+	ipmi_destroy_user(data->ipmi.user);
+ipmi_err:
+	platform_set_drvdata(data->pdev, NULL);
+	platform_device_unregister(data->pdev);
+dev_err:
+	ida_simple_remove(&aem_ida, data->id);
+id_err:
+	kfree(data);
+
+	return res;
+}
+
+/* Find and initialize all AEM1 instances */
+static void aem_init_aem1(struct aem_ipmi_data *probe)
+{
+	int num, i, err;
+
+	num = aem_find_aem1_count(probe);
+	for (i = 0; i < num; i++) {
+		err = aem_init_aem1_inst(probe, i);
+		if (err) {
+			dev_err(probe->bmc_device,
+				"Error %d initializing AEM1 0x%X\n",
+				err, i);
+		}
+	}
+}
+
+/* Probe functions for AEM2 devices */
+
+/* Retrieve version and module handle for an AEM2 instance */
+static int aem_find_aem2(struct aem_ipmi_data *data,
+			    struct aem_find_instance_resp *fi_resp,
+			    int instance_num)
+{
+	int res;
+	struct aem_find_instance_req fi_req;
+
+	fi_req.id = system_x_id;
+	fi_req.instance_number = instance_num;
+	fi_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID);
+
+	data->tx_message.cmd = AEM_FW_INSTANCE_CMD;
+	data->tx_message.data = (char *)&fi_req;
+	data->tx_message.data_len = sizeof(fi_req);
+
+	data->rx_msg_data = fi_resp;
+	data->rx_msg_len = sizeof(*fi_resp);
+
+	aem_send_message(data);
+
+	res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT);
+	if (!res)
+		return -ETIMEDOUT;
+
+	if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) ||
+	    memcmp(&fi_resp->id, &system_x_id, sizeof(system_x_id)) ||
+	    fi_resp->num_instances <= instance_num)
+		return -ENOENT;
+
+	return 0;
+}
+
+/* Find and initialize one AEM2 instance */
+static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
+			      struct aem_find_instance_resp *fi_resp)
+{
+	struct aem_data *data;
+	int i;
+	int res = -ENOMEM;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return res;
+	mutex_init(&data->lock);
+
+	/* Copy instance data */
+	data->ver_major = fi_resp->major;
+	data->ver_minor = fi_resp->minor;
+	data->module_handle = fi_resp->module_handle;
+	for (i = 0; i < AEM2_NUM_ENERGY_REGS; i++)
+		data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
+
+	/* Create sub-device for this fw instance */
+	data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL);
+	if (data->id < 0)
+		goto id_err;
+
+	data->pdev = platform_device_alloc(DRVNAME, data->id);
+	if (!data->pdev)
+		goto dev_err;
+	data->pdev->dev.driver = &aem_driver.driver;
+
+	res = platform_device_add(data->pdev);
+	if (res)
+		goto ipmi_err;
+
+	platform_set_drvdata(data->pdev, data);
+
+	/* Set up IPMI interface */
+	res = aem_init_ipmi_data(&data->ipmi, probe->interface,
+				 probe->bmc_device);
+	if (res)
+		goto ipmi_err;
+
+	/* Register with hwmon */
+	data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(&data->pdev->dev,
+			"Unable to register hwmon device for IPMI interface %d\n",
+			probe->interface);
+		res = PTR_ERR(data->hwmon_dev);
+		goto hwmon_reg_err;
+	}
+
+	data->update = update_aem2_sensors;
+	data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL);
+	if (!data->rs_resp) {
+		res = -ENOMEM;
+		goto alloc_resp_err;
+	}
+
+	/* Find sensors */
+	res = aem2_find_sensors(data);
+	if (res)
+		goto sensor_err;
+
+	/* Add to our list of AEM devices */
+	list_add_tail(&data->list, &driver_data.aem_devices);
+
+	dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n",
+		 data->ver_major, data->ver_minor,
+		 data->module_handle);
+	return 0;
+
+sensor_err:
+	kfree(data->rs_resp);
+alloc_resp_err:
+	hwmon_device_unregister(data->hwmon_dev);
+hwmon_reg_err:
+	ipmi_destroy_user(data->ipmi.user);
+ipmi_err:
+	platform_set_drvdata(data->pdev, NULL);
+	platform_device_unregister(data->pdev);
+dev_err:
+	ida_simple_remove(&aem_ida, data->id);
+id_err:
+	kfree(data);
+
+	return res;
+}
+
+/* Find and initialize all AEM2 instances */
+static void aem_init_aem2(struct aem_ipmi_data *probe)
+{
+	struct aem_find_instance_resp fi_resp;
+	int err;
+	int i = 0;
+
+	while (!aem_find_aem2(probe, &fi_resp, i)) {
+		if (fi_resp.major != 2) {
+			dev_err(probe->bmc_device,
+				"Unknown AEM v%d; please report this to the maintainer.\n",
+				fi_resp.major);
+			i++;
+			continue;
+		}
+		err = aem_init_aem2_inst(probe, &fi_resp);
+		if (err) {
+			dev_err(probe->bmc_device,
+				"Error %d initializing AEM2 0x%X\n",
+				err, fi_resp.module_handle);
+		}
+		i++;
+	}
+}
+
+/* Probe a BMC for AEM firmware instances */
+static void aem_register_bmc(int iface, struct device *dev)
+{
+	struct aem_ipmi_data probe;
+
+	if (aem_init_ipmi_data(&probe, iface, dev))
+		return;
+
+	/* Ignore probe errors; they won't cause problems */
+	aem_init_aem1(&probe);
+	aem_init_aem2(&probe);
+
+	ipmi_destroy_user(probe.user);
+}
+
+/* Handle BMC deletion */
+static void aem_bmc_gone(int iface)
+{
+	struct aem_data *p1, *next1;
+
+	list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list)
+		if (p1->ipmi.interface == iface)
+			aem_delete(p1);
+}
+
+/* sysfs support functions */
+
+/* AEM device name */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct aem_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s%d\n", DRVNAME, data->ver_major);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+/* AEM device version */
+static ssize_t show_version(struct device *dev,
+			    struct device_attribute *devattr,
+			    char *buf)
+{
+	struct aem_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d.%d\n", data->ver_major, data->ver_minor);
+}
+static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, 0);
+
+/* Display power use */
+static ssize_t aem_show_power(struct device *dev,
+			      struct device_attribute *devattr,
+			      char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *data = dev_get_drvdata(dev);
+	u64 before, after, delta, time;
+	signed long leftover;
+
+	mutex_lock(&data->lock);
+	update_aem_energy_one(data, attr->index);
+	time = ktime_get_ns();
+	before = data->energy[attr->index];
+
+	leftover = schedule_timeout_interruptible(
+			msecs_to_jiffies(data->power_period[attr->index])
+		   );
+	if (leftover) {
+		mutex_unlock(&data->lock);
+		return 0;
+	}
+
+	update_aem_energy_one(data, attr->index);
+	time = ktime_get_ns() - time;
+	after = data->energy[attr->index];
+	mutex_unlock(&data->lock);
+
+	delta = (after - before) * UJ_PER_MJ;
+
+	return sprintf(buf, "%llu\n",
+		(unsigned long long)div64_u64(delta * NSEC_PER_SEC, time));
+}
+
+/* Display energy use */
+static ssize_t aem_show_energy(struct device *dev,
+			       struct device_attribute *devattr,
+			       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *a = dev_get_drvdata(dev);
+	mutex_lock(&a->lock);
+	update_aem_energy_one(a, attr->index);
+	mutex_unlock(&a->lock);
+
+	return sprintf(buf, "%llu\n",
+			(unsigned long long)a->energy[attr->index] * 1000);
+}
+
+/* Display power interval registers */
+static ssize_t aem_show_power_period(struct device *dev,
+				     struct device_attribute *devattr,
+				     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *a = dev_get_drvdata(dev);
+	a->update(a);
+
+	return sprintf(buf, "%lu\n", a->power_period[attr->index]);
+}
+
+/* Set power interval registers */
+static ssize_t aem_set_power_period(struct device *dev,
+				    struct device_attribute *devattr,
+				    const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *a = dev_get_drvdata(dev);
+	unsigned long temp;
+	int res;
+
+	res = kstrtoul(buf, 10, &temp);
+	if (res)
+		return res;
+
+	if (temp < AEM_MIN_POWER_INTERVAL)
+		return -EINVAL;
+
+	mutex_lock(&a->lock);
+	a->power_period[attr->index] = temp;
+	mutex_unlock(&a->lock);
+
+	return count;
+}
+
+/* Discover sensors on an AEM device */
+static int aem_register_sensors(struct aem_data *data,
+				struct aem_ro_sensor_template *ro,
+				struct aem_rw_sensor_template *rw)
+{
+	struct device *dev = &data->pdev->dev;
+	struct sensor_device_attribute *sensors = data->sensors;
+	int err;
+
+	/* Set up read-only sensors */
+	while (ro->label) {
+		sysfs_attr_init(&sensors->dev_attr.attr);
+		sensors->dev_attr.attr.name = ro->label;
+		sensors->dev_attr.attr.mode = S_IRUGO;
+		sensors->dev_attr.show = ro->show;
+		sensors->index = ro->index;
+
+		err = device_create_file(dev, &sensors->dev_attr);
+		if (err) {
+			sensors->dev_attr.attr.name = NULL;
+			goto error;
+		}
+		sensors++;
+		ro++;
+	}
+
+	/* Set up read-write sensors */
+	while (rw->label) {
+		sysfs_attr_init(&sensors->dev_attr.attr);
+		sensors->dev_attr.attr.name = rw->label;
+		sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
+		sensors->dev_attr.show = rw->show;
+		sensors->dev_attr.store = rw->set;
+		sensors->index = rw->index;
+
+		err = device_create_file(dev, &sensors->dev_attr);
+		if (err) {
+			sensors->dev_attr.attr.name = NULL;
+			goto error;
+		}
+		sensors++;
+		rw++;
+	}
+
+	err = device_create_file(dev, &sensor_dev_attr_name.dev_attr);
+	if (err)
+		goto error;
+	err = device_create_file(dev, &sensor_dev_attr_version.dev_attr);
+	return err;
+
+error:
+	aem_remove_sensors(data);
+	return err;
+}
+
+/* sysfs support functions for AEM2 sensors */
+
+/* Display temperature use */
+static ssize_t aem2_show_temp(struct device *dev,
+			      struct device_attribute *devattr,
+			      char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *a = dev_get_drvdata(dev);
+	a->update(a);
+
+	return sprintf(buf, "%u\n", a->temp[attr->index] * 1000);
+}
+
+/* Display power-capping registers */
+static ssize_t aem2_show_pcap_value(struct device *dev,
+				    struct device_attribute *devattr,
+				    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct aem_data *a = dev_get_drvdata(dev);
+	a->update(a);
+
+	return sprintf(buf, "%u\n", a->pcap[attr->index] * 100000);
+}
+
+/* Remove sensors attached to an AEM device */
+static void aem_remove_sensors(struct aem_data *data)
+{
+	int i;
+
+	for (i = 0; i < AEM_NUM_SENSORS; i++) {
+		if (!data->sensors[i].dev_attr.attr.name)
+			continue;
+		device_remove_file(&data->pdev->dev,
+				   &data->sensors[i].dev_attr);
+	}
+
+	device_remove_file(&data->pdev->dev,
+			   &sensor_dev_attr_name.dev_attr);
+	device_remove_file(&data->pdev->dev,
+			   &sensor_dev_attr_version.dev_attr);
+}
+
+/* Sensor probe functions */
+
+/* Description of AEM1 sensors */
+static struct aem_ro_sensor_template aem1_ro_sensors[] = {
+{"energy1_input",  aem_show_energy, 0},
+{"power1_average", aem_show_power,  0},
+{NULL,		   NULL,	    0},
+};
+
+static struct aem_rw_sensor_template aem1_rw_sensors[] = {
+{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
+{NULL,			    NULL,                  NULL,                 0},
+};
+
+/* Description of AEM2 sensors */
+static struct aem_ro_sensor_template aem2_ro_sensors[] = {
+{"energy1_input",	  aem_show_energy,	0},
+{"energy2_input",	  aem_show_energy,	1},
+{"power1_average",	  aem_show_power,	0},
+{"power2_average",	  aem_show_power,	1},
+{"temp1_input",		  aem2_show_temp,	0},
+{"temp2_input",		  aem2_show_temp,	1},
+
+{"power4_average",	  aem2_show_pcap_value,	POWER_CAP_MAX_HOTPLUG},
+{"power5_average",	  aem2_show_pcap_value,	POWER_CAP_MAX},
+{"power6_average",	  aem2_show_pcap_value,	POWER_CAP_MIN_WARNING},
+{"power7_average",	  aem2_show_pcap_value,	POWER_CAP_MIN},
+
+{"power3_average",	  aem2_show_pcap_value,	POWER_AUX},
+{"power_cap",		  aem2_show_pcap_value,	POWER_CAP},
+{NULL,                    NULL,                 0},
+};
+
+static struct aem_rw_sensor_template aem2_rw_sensors[] = {
+{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
+{"power2_average_interval", aem_show_power_period, aem_set_power_period, 1},
+{NULL,			    NULL,                  NULL,                 0},
+};
+
+/* Set up AEM1 sensor attrs */
+static int aem1_find_sensors(struct aem_data *data)
+{
+	return aem_register_sensors(data, aem1_ro_sensors, aem1_rw_sensors);
+}
+
+/* Set up AEM2 sensor attrs */
+static int aem2_find_sensors(struct aem_data *data)
+{
+	return aem_register_sensors(data, aem2_ro_sensors, aem2_rw_sensors);
+}
+
+/* Module init/exit routines */
+
+static int __init aem_init(void)
+{
+	int res;
+
+	res = driver_register(&aem_driver.driver);
+	if (res) {
+		pr_err("Can't register aem driver\n");
+		return res;
+	}
+
+	res = ipmi_smi_watcher_register(&driver_data.bmc_events);
+	if (res)
+		goto ipmi_reg_err;
+	return 0;
+
+ipmi_reg_err:
+	driver_unregister(&aem_driver.driver);
+	return res;
+
+}
+
+static void __exit aem_exit(void)
+{
+	struct aem_data *p1, *next1;
+
+	ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+	driver_unregister(&aem_driver.driver);
+	list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list)
+		aem_delete(p1);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("IBM AEM power/temp/energy sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(aem_init);
+module_exit(aem_exit);
+
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3350-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*");
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
new file mode 100644
index 0000000..21b9c72
--- /dev/null
+++ b/drivers/hwmon/ibmpex.c
@@ -0,0 +1,615 @@
+/*
+ * A hwmon driver for the IBM PowerExecutive temperature/power sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#define REFRESH_INTERVAL	(2 * HZ)
+#define DRVNAME			"ibmpex"
+
+#define PEX_GET_VERSION		1
+#define PEX_GET_SENSOR_COUNT	2
+#define PEX_GET_SENSOR_NAME	3
+#define PEX_RESET_HIGH_LOW	4
+#define PEX_GET_SENSOR_DATA	6
+
+#define PEX_NET_FUNCTION	0x3A
+#define PEX_COMMAND		0x3C
+
+static inline u16 extract_value(const char *data, int offset)
+{
+	return be16_to_cpup((__be16 *)&data[offset]);
+}
+
+#define TEMP_SENSOR		1
+#define POWER_SENSOR		2
+
+#define PEX_SENSOR_TYPE_LEN	3
+static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
+static u8 const temp_sensor_sig[]  = {0x74, 0x65, 0x6D};
+
+#define PEX_MULT_LEN		2
+static u8 const watt_sensor_sig[]  = {0x41, 0x43};
+
+#define PEX_NUM_SENSOR_FUNCS	3
+static const char * const sensor_name_suffixes[] = {
+	"",
+	"_lowest",
+	"_highest"
+};
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void ibmpex_register_bmc(int iface, struct device *dev);
+static void ibmpex_bmc_gone(int iface);
+
+struct ibmpex_sensor_data {
+	int			in_use;
+	s16			values[PEX_NUM_SENSOR_FUNCS];
+	int			multiplier;
+
+	struct sensor_device_attribute_2	attr[PEX_NUM_SENSOR_FUNCS];
+};
+
+struct ibmpex_bmc_data {
+	struct list_head	list;
+	struct device		*hwmon_dev;
+	struct device		*bmc_device;
+	struct mutex		lock;
+	char			valid;
+	unsigned long		last_updated;	/* In jiffies */
+
+	struct ipmi_addr	address;
+	struct completion	read_complete;
+	ipmi_user_t		user;
+	int			interface;
+
+	struct kernel_ipmi_msg	tx_message;
+	unsigned char		tx_msg_data[IPMI_MAX_MSG_LENGTH];
+	long			tx_msgid;
+
+	unsigned char		rx_msg_data[IPMI_MAX_MSG_LENGTH];
+	unsigned long		rx_msg_len;
+	unsigned char		rx_result;
+	int			rx_recv_type;
+
+	unsigned char		sensor_major;
+	unsigned char		sensor_minor;
+
+	unsigned char		num_sensors;
+	struct ibmpex_sensor_data	*sensors;
+};
+
+struct ibmpex_driver_data {
+	struct list_head	bmc_data;
+	struct ipmi_smi_watcher	bmc_events;
+	struct ipmi_user_hndl	ipmi_hndlrs;
+};
+
+static struct ibmpex_driver_data driver_data = {
+	.bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
+	.bmc_events = {
+		.owner = THIS_MODULE,
+		.new_smi = ibmpex_register_bmc,
+		.smi_gone = ibmpex_bmc_gone,
+	},
+	.ipmi_hndlrs = {
+		.ipmi_recv_hndl = ibmpex_msg_handler,
+	},
+};
+
+static int ibmpex_send_message(struct ibmpex_bmc_data *data)
+{
+	int err;
+
+	err = ipmi_validate_addr(&data->address, sizeof(data->address));
+	if (err)
+		goto out;
+
+	data->tx_msgid++;
+	err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+				   &data->tx_message, data, 0, 0, 0);
+	if (err)
+		goto out1;
+
+	return 0;
+out1:
+	dev_err(data->bmc_device, "request_settime=%x\n", err);
+	return err;
+out:
+	dev_err(data->bmc_device, "validate_addr=%x\n", err);
+	return err;
+}
+
+static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
+{
+	data->tx_msg_data[0] = PEX_GET_VERSION;
+	data->tx_message.data_len = 1;
+	ibmpex_send_message(data);
+
+	wait_for_completion(&data->read_complete);
+
+	if (data->rx_result || data->rx_msg_len != 6)
+		return -ENOENT;
+
+	data->sensor_major = data->rx_msg_data[0];
+	data->sensor_minor = data->rx_msg_data[1];
+
+	dev_info(data->bmc_device,
+		 "Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
+		 data->sensor_major,
+		 data->sensor_minor,
+		 extract_value(data->rx_msg_data, 2),
+		 data->rx_msg_data[4],
+		 data->rx_msg_data[5],
+		 data->interface);
+
+	return 0;
+}
+
+static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
+{
+	data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
+	data->tx_message.data_len = 1;
+	ibmpex_send_message(data);
+
+	wait_for_completion(&data->read_complete);
+
+	if (data->rx_result || data->rx_msg_len != 1)
+		return -ENOENT;
+
+	return data->rx_msg_data[0];
+}
+
+static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
+{
+	data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
+	data->tx_msg_data[1] = sensor;
+	data->tx_message.data_len = 2;
+	ibmpex_send_message(data);
+
+	wait_for_completion(&data->read_complete);
+
+	if (data->rx_result || data->rx_msg_len < 1)
+		return -ENOENT;
+
+	return 0;
+}
+
+static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
+{
+	data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
+	data->tx_msg_data[1] = sensor;
+	data->tx_message.data_len = 2;
+	ibmpex_send_message(data);
+
+	wait_for_completion(&data->read_complete);
+
+	if (data->rx_result || data->rx_msg_len < 26) {
+		dev_err(data->bmc_device, "Error reading sensor %d.\n",
+			sensor);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
+{
+	data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
+	data->tx_message.data_len = 1;
+	ibmpex_send_message(data);
+
+	wait_for_completion(&data->read_complete);
+
+	return 0;
+}
+
+static void ibmpex_update_device(struct ibmpex_bmc_data *data)
+{
+	int i, err;
+
+	mutex_lock(&data->lock);
+	if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+	    data->valid)
+		goto out;
+
+	for (i = 0; i < data->num_sensors; i++) {
+		if (!data->sensors[i].in_use)
+			continue;
+		err = ibmpex_query_sensor_data(data, i);
+		if (err)
+			continue;
+		data->sensors[i].values[0] =
+			extract_value(data->rx_msg_data, 16);
+		data->sensors[i].values[1] =
+			extract_value(data->rx_msg_data, 18);
+		data->sensors[i].values[2] =
+			extract_value(data->rx_msg_data, 20);
+	}
+
+	data->last_updated = jiffies;
+	data->valid = 1;
+
+out:
+	mutex_unlock(&data->lock);
+}
+
+static struct ibmpex_bmc_data *get_bmc_data(int iface)
+{
+	struct ibmpex_bmc_data *p, *next;
+
+	list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+		if (p->interface == iface)
+			return p;
+
+	return NULL;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	return sprintf(buf, "%s\n", DRVNAME);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static ssize_t ibmpex_show_sensor(struct device *dev,
+				  struct device_attribute *devattr,
+				  char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+	int mult = data->sensors[attr->index].multiplier;
+	ibmpex_update_device(data);
+
+	return sprintf(buf, "%d\n",
+		       data->sensors[attr->index].values[attr->nr] * mult);
+}
+
+static ssize_t ibmpex_reset_high_low(struct device *dev,
+				     struct device_attribute *devattr,
+				     const char *buf,
+				     size_t count)
+{
+	struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+
+	ibmpex_reset_high_low_data(data);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL,
+			  ibmpex_reset_high_low, 0);
+
+static int is_power_sensor(const char *sensor_id, int len)
+{
+	if (len < PEX_SENSOR_TYPE_LEN)
+		return 0;
+
+	if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
+		return 1;
+	return 0;
+}
+
+static int is_temp_sensor(const char *sensor_id, int len)
+{
+	if (len < PEX_SENSOR_TYPE_LEN)
+		return 0;
+
+	if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
+		return 1;
+	return 0;
+}
+
+static int power_sensor_multiplier(struct ibmpex_bmc_data *data,
+				   const char *sensor_id, int len)
+{
+	int i;
+
+	if (data->sensor_major == 2)
+		return 1000000;
+
+	for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
+		if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
+			return 1000000;
+
+	return 100000;
+}
+
+static int create_sensor(struct ibmpex_bmc_data *data, int type,
+			 int counter, int sensor, int func)
+{
+	int err;
+	char *n;
+
+	n = kmalloc(32, GFP_KERNEL);
+	if (!n)
+		return -ENOMEM;
+
+	if (type == TEMP_SENSOR)
+		sprintf(n, "temp%d_input%s",
+			counter, sensor_name_suffixes[func]);
+	else if (type == POWER_SENSOR)
+		sprintf(n, "power%d_average%s",
+			counter, sensor_name_suffixes[func]);
+
+	sysfs_attr_init(&data->sensors[sensor].attr[func].dev_attr.attr);
+	data->sensors[sensor].attr[func].dev_attr.attr.name = n;
+	data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
+	data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
+	data->sensors[sensor].attr[func].index = sensor;
+	data->sensors[sensor].attr[func].nr = func;
+
+	err = device_create_file(data->bmc_device,
+				 &data->sensors[sensor].attr[func].dev_attr);
+	if (err) {
+		data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
+		kfree(n);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
+{
+	int i, j, err;
+	int sensor_type;
+	int sensor_counter;
+	int num_power = 0;
+	int num_temp = 0;
+
+	err = ibmpex_query_sensor_count(data);
+	if (err <= 0)
+		return -ENOENT;
+	data->num_sensors = err;
+
+	data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors),
+				GFP_KERNEL);
+	if (!data->sensors)
+		return -ENOMEM;
+
+	for (i = 0; i < data->num_sensors; i++) {
+		err = ibmpex_query_sensor_name(data, i);
+		if (err)
+			continue;
+
+		if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
+			sensor_type = POWER_SENSOR;
+			num_power++;
+			sensor_counter = num_power;
+			data->sensors[i].multiplier =
+				power_sensor_multiplier(data,
+							data->rx_msg_data,
+							data->rx_msg_len);
+		} else if (is_temp_sensor(data->rx_msg_data,
+					  data->rx_msg_len)) {
+			sensor_type = TEMP_SENSOR;
+			num_temp++;
+			sensor_counter = num_temp;
+			data->sensors[i].multiplier = 1000;
+		} else
+			continue;
+
+		data->sensors[i].in_use = 1;
+
+		/* Create attributes */
+		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+			err = create_sensor(data, sensor_type, sensor_counter,
+					    i, j);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	err = device_create_file(data->bmc_device,
+			&sensor_dev_attr_reset_high_low.dev_attr);
+	if (err)
+		goto exit_remove;
+
+	err = device_create_file(data->bmc_device,
+			&sensor_dev_attr_name.dev_attr);
+	if (err)
+		goto exit_remove;
+
+	return 0;
+
+exit_remove:
+	device_remove_file(data->bmc_device,
+			   &sensor_dev_attr_reset_high_low.dev_attr);
+	device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+	for (i = 0; i < data->num_sensors; i++)
+		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+			if (!data->sensors[i].attr[j].dev_attr.attr.name)
+				continue;
+			device_remove_file(data->bmc_device,
+				&data->sensors[i].attr[j].dev_attr);
+			kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+		}
+
+	kfree(data->sensors);
+	return err;
+}
+
+static void ibmpex_register_bmc(int iface, struct device *dev)
+{
+	struct ibmpex_bmc_data *data;
+	int err;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return;
+
+	data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	data->address.channel = IPMI_BMC_CHANNEL;
+	data->address.data[0] = 0;
+	data->interface = iface;
+	data->bmc_device = dev;
+
+	/* Create IPMI messaging interface user */
+	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+			       data, &data->user);
+	if (err < 0) {
+		dev_err(dev,
+			"Unable to register user with IPMI interface %d\n",
+			data->interface);
+		goto out;
+	}
+
+	mutex_init(&data->lock);
+
+	/* Initialize message */
+	data->tx_msgid = 0;
+	init_completion(&data->read_complete);
+	data->tx_message.netfn = PEX_NET_FUNCTION;
+	data->tx_message.cmd = PEX_COMMAND;
+	data->tx_message.data = data->tx_msg_data;
+
+	/* Does this BMC support PowerExecutive? */
+	err = ibmpex_ver_check(data);
+	if (err)
+		goto out_user;
+
+	/* Register the BMC as a HWMON class device */
+	data->hwmon_dev = hwmon_device_register(data->bmc_device);
+
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(data->bmc_device,
+			"Unable to register hwmon device for IPMI interface %d\n",
+			data->interface);
+		goto out_user;
+	}
+
+	/* finally add the new bmc data to the bmc data list */
+	dev_set_drvdata(dev, data);
+	list_add_tail(&data->list, &driver_data.bmc_data);
+
+	/* Now go find all the sensors */
+	err = ibmpex_find_sensors(data);
+	if (err) {
+		dev_err(data->bmc_device, "Error %d finding sensors\n", err);
+		goto out_register;
+	}
+
+	return;
+
+out_register:
+	hwmon_device_unregister(data->hwmon_dev);
+out_user:
+	ipmi_destroy_user(data->user);
+out:
+	kfree(data);
+}
+
+static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
+{
+	int i, j;
+
+	device_remove_file(data->bmc_device,
+			   &sensor_dev_attr_reset_high_low.dev_attr);
+	device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+	for (i = 0; i < data->num_sensors; i++)
+		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+			if (!data->sensors[i].attr[j].dev_attr.attr.name)
+				continue;
+			device_remove_file(data->bmc_device,
+				&data->sensors[i].attr[j].dev_attr);
+			kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+		}
+
+	list_del(&data->list);
+	dev_set_drvdata(data->bmc_device, NULL);
+	hwmon_device_unregister(data->hwmon_dev);
+	ipmi_destroy_user(data->user);
+	kfree(data->sensors);
+	kfree(data);
+}
+
+static void ibmpex_bmc_gone(int iface)
+{
+	struct ibmpex_bmc_data *data = get_bmc_data(iface);
+
+	if (!data)
+		return;
+
+	ibmpex_bmc_delete(data);
+}
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+	struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
+
+	if (msg->msgid != data->tx_msgid) {
+		dev_err(data->bmc_device,
+			"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
+			(int)msg->msgid,
+			(int)data->tx_msgid);
+		ipmi_free_recv_msg(msg);
+		return;
+	}
+
+	data->rx_recv_type = msg->recv_type;
+	if (msg->msg.data_len > 0)
+		data->rx_result = msg->msg.data[0];
+	else
+		data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+	if (msg->msg.data_len > 1) {
+		data->rx_msg_len = msg->msg.data_len - 1;
+		memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+	} else
+		data->rx_msg_len = 0;
+
+	ipmi_free_recv_msg(msg);
+	complete(&data->read_complete);
+}
+
+static int __init ibmpex_init(void)
+{
+	return ipmi_smi_watcher_register(&driver_data.bmc_events);
+}
+
+static void __exit ibmpex_exit(void)
+{
+	struct ibmpex_bmc_data *p, *next;
+
+	ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+	list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+		ibmpex_bmc_delete(p);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
+MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(ibmpex_init);
+module_exit(ibmpex_exit);
+
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3350-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
new file mode 100644
index 0000000..55b5a8f
--- /dev/null
+++ b/drivers/hwmon/ibmpowernv.c
@@ -0,0 +1,496 @@
+/*
+ * IBM PowerNV platform sensors for temperature/fan/voltage/power
+ * Copyright (C) 2014 IBM
+ *
+ * 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.
+ */
+
+#define DRVNAME		"ibmpowernv"
+#define pr_fmt(fmt)	DRVNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <asm/opal.h>
+#include <linux/err.h>
+#include <asm/cputhreads.h>
+#include <asm/smp.h>
+
+#define MAX_ATTR_LEN	32
+#define MAX_LABEL_LEN	64
+
+/* Sensor suffix name from DT */
+#define DT_FAULT_ATTR_SUFFIX		"faulted"
+#define DT_DATA_ATTR_SUFFIX		"data"
+#define DT_THRESHOLD_ATTR_SUFFIX	"thrs"
+
+/*
+ * Enumerates all the types of sensors in the POWERNV platform and does index
+ * into 'struct sensor_group'
+ */
+enum sensors {
+	FAN,
+	TEMP,
+	POWER_SUPPLY,
+	POWER_INPUT,
+	MAX_SENSOR_TYPE,
+};
+
+#define INVALID_INDEX (-1U)
+
+static struct sensor_group {
+	const char *name;
+	const char *compatible;
+	struct attribute_group group;
+	u32 attr_count;
+	u32 hwmon_index;
+} sensor_groups[] = {
+	{"fan", "ibm,opal-sensor-cooling-fan"},
+	{"temp", "ibm,opal-sensor-amb-temp"},
+	{"in", "ibm,opal-sensor-power-supply"},
+	{"power", "ibm,opal-sensor-power"}
+};
+
+struct sensor_data {
+	u32 id; /* An opaque id of the firmware for each sensor */
+	u32 hwmon_index;
+	u32 opal_index;
+	enum sensors type;
+	char label[MAX_LABEL_LEN];
+	char name[MAX_ATTR_LEN];
+	struct device_attribute dev_attr;
+};
+
+struct platform_data {
+	const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
+	u32 sensors_count; /* Total count of sensors from each group */
+};
+
+static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
+			   char *buf)
+{
+	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
+						 dev_attr);
+	ssize_t ret;
+	u32 x;
+
+	ret = opal_get_sensor_data(sdata->id, &x);
+	if (ret)
+		return ret;
+
+	/* Convert temperature to milli-degrees */
+	if (sdata->type == TEMP)
+		x *= 1000;
+	/* Convert power to micro-watts */
+	else if (sdata->type == POWER_INPUT)
+		x *= 1000000;
+
+	return sprintf(buf, "%u\n", x);
+}
+
+static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
+						 dev_attr);
+
+	return sprintf(buf, "%s\n", sdata->label);
+}
+
+static int __init get_logical_cpu(int hwcpu)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		if (get_hard_smp_processor_id(cpu) == hwcpu)
+			return cpu;
+
+	return -ENOENT;
+}
+
+static void __init make_sensor_label(struct device_node *np,
+				     struct sensor_data *sdata,
+				     const char *label)
+{
+	u32 id;
+	size_t n;
+
+	n = snprintf(sdata->label, sizeof(sdata->label), "%s", label);
+
+	/*
+	 * Core temp pretty print
+	 */
+	if (!of_property_read_u32(np, "ibm,pir", &id)) {
+		int cpuid = get_logical_cpu(id);
+
+		if (cpuid >= 0)
+			/*
+			 * The digital thermal sensors are associated
+			 * with a core. Let's print out the range of
+			 * cpu ids corresponding to the hardware
+			 * threads of the core.
+			 */
+			n += snprintf(sdata->label + n,
+				      sizeof(sdata->label) - n, " %d-%d",
+				      cpuid, cpuid + threads_per_core - 1);
+		else
+			n += snprintf(sdata->label + n,
+				      sizeof(sdata->label) - n, " phy%d", id);
+	}
+
+	/*
+	 * Membuffer pretty print
+	 */
+	if (!of_property_read_u32(np, "ibm,chip-id", &id))
+		n += snprintf(sdata->label + n, sizeof(sdata->label) - n,
+			      " %d", id & 0xffff);
+}
+
+static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
+{
+	char *hash_pos = strchr(name, '#');
+	char buf[8] = { 0 };
+	char *dash_pos;
+	u32 copy_len;
+	int err;
+
+	if (!hash_pos)
+		return -EINVAL;
+
+	dash_pos = strchr(hash_pos, '-');
+	if (!dash_pos)
+		return -EINVAL;
+
+	copy_len = dash_pos - hash_pos - 1;
+	if (copy_len >= sizeof(buf))
+		return -EINVAL;
+
+	strncpy(buf, hash_pos + 1, copy_len);
+
+	err = kstrtou32(buf, 10, index);
+	if (err)
+		return err;
+
+	strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
+
+	return 0;
+}
+
+static const char *convert_opal_attr_name(enum sensors type,
+					  const char *opal_attr)
+{
+	const char *attr_name = NULL;
+
+	if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) {
+		attr_name = "fault";
+	} else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) {
+		attr_name = "input";
+	} else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) {
+		if (type == TEMP)
+			attr_name = "max";
+		else if (type == FAN)
+			attr_name = "min";
+	}
+
+	return attr_name;
+}
+
+/*
+ * This function translates the DT node name into the 'hwmon' attribute name.
+ * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
+ * which need to be mapped as fan2_input, temp1_max respectively before
+ * populating them inside hwmon device class.
+ */
+static const char *parse_opal_node_name(const char *node_name,
+					enum sensors type, u32 *index)
+{
+	char attr_suffix[MAX_ATTR_LEN];
+	const char *attr_name;
+	int err;
+
+	err = get_sensor_index_attr(node_name, index, attr_suffix);
+	if (err)
+		return ERR_PTR(err);
+
+	attr_name = convert_opal_attr_name(type, attr_suffix);
+	if (!attr_name)
+		return ERR_PTR(-ENOENT);
+
+	return attr_name;
+}
+
+static int get_sensor_type(struct device_node *np)
+{
+	enum sensors type;
+	const char *str;
+
+	for (type = 0; type < MAX_SENSOR_TYPE; type++) {
+		if (of_device_is_compatible(np, sensor_groups[type].compatible))
+			return type;
+	}
+
+	/*
+	 * Let's check if we have a newer device tree
+	 */
+	if (!of_device_is_compatible(np, "ibm,opal-sensor"))
+		return MAX_SENSOR_TYPE;
+
+	if (of_property_read_string(np, "sensor-type", &str))
+		return MAX_SENSOR_TYPE;
+
+	for (type = 0; type < MAX_SENSOR_TYPE; type++)
+		if (!strcmp(str, sensor_groups[type].name))
+			return type;
+
+	return MAX_SENSOR_TYPE;
+}
+
+static u32 get_sensor_hwmon_index(struct sensor_data *sdata,
+				  struct sensor_data *sdata_table, int count)
+{
+	int i;
+
+	/*
+	 * We don't use the OPAL index on newer device trees
+	 */
+	if (sdata->opal_index != INVALID_INDEX) {
+		for (i = 0; i < count; i++)
+			if (sdata_table[i].opal_index == sdata->opal_index &&
+			    sdata_table[i].type == sdata->type)
+				return sdata_table[i].hwmon_index;
+	}
+	return ++sensor_groups[sdata->type].hwmon_index;
+}
+
+static int populate_attr_groups(struct platform_device *pdev)
+{
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	const struct attribute_group **pgroups = pdata->attr_groups;
+	struct device_node *opal, *np;
+	enum sensors type;
+
+	opal = of_find_node_by_path("/ibm,opal/sensors");
+	for_each_child_of_node(opal, np) {
+		const char *label;
+
+		if (np->name == NULL)
+			continue;
+
+		type = get_sensor_type(np);
+		if (type == MAX_SENSOR_TYPE)
+			continue;
+
+		sensor_groups[type].attr_count++;
+
+		/*
+		 * add a new attribute for labels
+		 */
+		if (!of_property_read_string(np, "label", &label))
+			sensor_groups[type].attr_count++;
+	}
+
+	of_node_put(opal);
+
+	for (type = 0; type < MAX_SENSOR_TYPE; type++) {
+		sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev,
+					sizeof(struct attribute *) *
+					(sensor_groups[type].attr_count + 1),
+					GFP_KERNEL);
+		if (!sensor_groups[type].group.attrs)
+			return -ENOMEM;
+
+		pgroups[type] = &sensor_groups[type].group;
+		pdata->sensors_count += sensor_groups[type].attr_count;
+		sensor_groups[type].attr_count = 0;
+	}
+
+	return 0;
+}
+
+static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name,
+			      ssize_t (*show)(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf))
+{
+	snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s",
+		 sensor_groups[sdata->type].name, sdata->hwmon_index,
+		 attr_name);
+
+	sysfs_attr_init(&sdata->dev_attr.attr);
+	sdata->dev_attr.attr.name = sdata->name;
+	sdata->dev_attr.attr.mode = S_IRUGO;
+	sdata->dev_attr.show = show;
+}
+
+/*
+ * Iterate through the device tree for each child of 'sensors' node, create
+ * a sysfs attribute file, the file is named by translating the DT node name
+ * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
+ * etc..
+ */
+static int create_device_attrs(struct platform_device *pdev)
+{
+	struct platform_data *pdata = platform_get_drvdata(pdev);
+	const struct attribute_group **pgroups = pdata->attr_groups;
+	struct device_node *opal, *np;
+	struct sensor_data *sdata;
+	u32 sensor_id;
+	enum sensors type;
+	u32 count = 0;
+	int err = 0;
+
+	opal = of_find_node_by_path("/ibm,opal/sensors");
+	sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata),
+			     GFP_KERNEL);
+	if (!sdata) {
+		err = -ENOMEM;
+		goto exit_put_node;
+	}
+
+	for_each_child_of_node(opal, np) {
+		const char *attr_name;
+		u32 opal_index;
+		const char *label;
+
+		if (np->name == NULL)
+			continue;
+
+		type = get_sensor_type(np);
+		if (type == MAX_SENSOR_TYPE)
+			continue;
+
+		/*
+		 * Newer device trees use a "sensor-data" property
+		 * name for input.
+		 */
+		if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
+		    of_property_read_u32(np, "sensor-data", &sensor_id)) {
+			dev_info(&pdev->dev,
+				 "'sensor-id' missing in the node '%s'\n",
+				 np->name);
+			continue;
+		}
+
+		sdata[count].id = sensor_id;
+		sdata[count].type = type;
+
+		/*
+		 * If we can not parse the node name, it means we are
+		 * running on a newer device tree. We can just forget
+		 * about the OPAL index and use a defaut value for the
+		 * hwmon attribute name
+		 */
+		attr_name = parse_opal_node_name(np->name, type, &opal_index);
+		if (IS_ERR(attr_name)) {
+			attr_name = "input";
+			opal_index = INVALID_INDEX;
+		}
+
+		sdata[count].opal_index = opal_index;
+		sdata[count].hwmon_index =
+			get_sensor_hwmon_index(&sdata[count], sdata, count);
+
+		create_hwmon_attr(&sdata[count], attr_name, show_sensor);
+
+		pgroups[type]->attrs[sensor_groups[type].attr_count++] =
+				&sdata[count++].dev_attr.attr;
+
+		if (!of_property_read_string(np, "label", &label)) {
+			/*
+			 * For the label attribute, we can reuse the
+			 * "properties" of the previous "input"
+			 * attribute. They are related to the same
+			 * sensor.
+			 */
+			sdata[count].type = type;
+			sdata[count].opal_index = sdata[count - 1].opal_index;
+			sdata[count].hwmon_index = sdata[count - 1].hwmon_index;
+
+			make_sensor_label(np, &sdata[count], label);
+
+			create_hwmon_attr(&sdata[count], "label", show_label);
+
+			pgroups[type]->attrs[sensor_groups[type].attr_count++] =
+				&sdata[count++].dev_attr.attr;
+		}
+	}
+
+exit_put_node:
+	of_node_put(opal);
+	return err;
+}
+
+static int ibmpowernv_probe(struct platform_device *pdev)
+{
+	struct platform_data *pdata;
+	struct device *hwmon_dev;
+	int err;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, pdata);
+	pdata->sensors_count = 0;
+	err = populate_attr_groups(pdev);
+	if (err)
+		return err;
+
+	/* Create sysfs attribute data for each sensor found in the DT */
+	err = create_device_attrs(pdev);
+	if (err)
+		return err;
+
+	/* Finally, register with hwmon */
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
+							   pdata,
+							   pdata->attr_groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct platform_device_id opal_sensor_driver_ids[] = {
+	{
+		.name = "opal-sensor",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
+
+static const struct of_device_id opal_sensor_match[] = {
+	{ .compatible	= "ibm,opal-sensor" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, opal_sensor_match);
+
+static struct platform_driver ibmpowernv_driver = {
+	.probe		= ibmpowernv_probe,
+	.id_table	= opal_sensor_driver_ids,
+	.driver		= {
+		.name	= DRVNAME,
+		.of_match_table	= opal_sensor_match,
+	},
+};
+
+module_platform_driver(ibmpowernv_driver);
+
+MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IBM POWERNV platform sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
new file mode 100644
index 0000000..d5c06f2
--- /dev/null
+++ b/drivers/hwmon/iio_hwmon.c
@@ -0,0 +1,190 @@
+/* Hwmon client for industrial I/O devices
+ *
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/of.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
+
+/**
+ * struct iio_hwmon_state - device instance state
+ * @channels:		filled with array of channels from iio
+ * @num_channels:	number of channels in channels (saves counting twice)
+ * @hwmon_dev:		associated hwmon device
+ * @attr_group:	the group of attributes
+ * @attrs:		null terminated array of attribute pointers.
+ */
+struct iio_hwmon_state {
+	struct iio_channel *channels;
+	int num_channels;
+	struct device *hwmon_dev;
+	struct attribute_group attr_group;
+	const struct attribute_group *groups[2];
+	struct attribute **attrs;
+};
+
+/*
+ * Assumes that IIO and hwmon operate in the same base units.
+ * This is supposed to be true, but needs verification for
+ * new channel types.
+ */
+static ssize_t iio_hwmon_read_val(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	int result;
+	int ret;
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct iio_hwmon_state *state = dev_get_drvdata(dev);
+
+	ret = iio_read_channel_processed(&state->channels[sattr->index],
+					&result);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", result);
+}
+
+static int iio_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct iio_hwmon_state *st;
+	struct sensor_device_attribute *a;
+	int ret, i;
+	int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
+	enum iio_chan_type type;
+	struct iio_channel *channels;
+	const char *name = "iio_hwmon";
+
+	if (dev->of_node && dev->of_node->name)
+		name = dev->of_node->name;
+
+	channels = iio_channel_get_all(dev);
+	if (IS_ERR(channels))
+		return PTR_ERR(channels);
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (st == NULL) {
+		ret = -ENOMEM;
+		goto error_release_channels;
+	}
+
+	st->channels = channels;
+
+	/* count how many attributes we have */
+	while (st->channels[st->num_channels].indio_dev)
+		st->num_channels++;
+
+	st->attrs = devm_kzalloc(dev,
+				 sizeof(*st->attrs) * (st->num_channels + 1),
+				 GFP_KERNEL);
+	if (st->attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_release_channels;
+	}
+
+	for (i = 0; i < st->num_channels; i++) {
+		a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL);
+		if (a == NULL) {
+			ret = -ENOMEM;
+			goto error_release_channels;
+		}
+
+		sysfs_attr_init(&a->dev_attr.attr);
+		ret = iio_get_channel_type(&st->channels[i], &type);
+		if (ret < 0)
+			goto error_release_channels;
+
+		switch (type) {
+		case IIO_VOLTAGE:
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "in%d_input",
+							       in_i++);
+			break;
+		case IIO_TEMP:
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "temp%d_input",
+							       temp_i++);
+			break;
+		case IIO_CURRENT:
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "curr%d_input",
+							       curr_i++);
+			break;
+		case IIO_HUMIDITYRELATIVE:
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "humidity%d_input",
+							       humidity_i++);
+			break;
+		default:
+			ret = -EINVAL;
+			goto error_release_channels;
+		}
+		if (a->dev_attr.attr.name == NULL) {
+			ret = -ENOMEM;
+			goto error_release_channels;
+		}
+		a->dev_attr.show = iio_hwmon_read_val;
+		a->dev_attr.attr.mode = S_IRUGO;
+		a->index = i;
+		st->attrs[i] = &a->dev_attr.attr;
+	}
+
+	st->attr_group.attrs = st->attrs;
+	st->groups[0] = &st->attr_group;
+	st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
+							  st->groups);
+	if (IS_ERR(st->hwmon_dev)) {
+		ret = PTR_ERR(st->hwmon_dev);
+		goto error_release_channels;
+	}
+	platform_set_drvdata(pdev, st);
+	return 0;
+
+error_release_channels:
+	iio_channel_release_all(channels);
+	return ret;
+}
+
+static int iio_hwmon_remove(struct platform_device *pdev)
+{
+	struct iio_hwmon_state *st = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(st->hwmon_dev);
+	iio_channel_release_all(st->channels);
+
+	return 0;
+}
+
+static const struct of_device_id iio_hwmon_of_match[] = {
+	{ .compatible = "iio-hwmon", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, iio_hwmon_of_match);
+
+static struct platform_driver __refdata iio_hwmon_driver = {
+	.driver = {
+		.name = "iio_hwmon",
+		.of_match_table = iio_hwmon_of_match,
+	},
+	.probe = iio_hwmon_probe,
+	.remove = iio_hwmon_remove,
+};
+
+module_platform_driver(iio_hwmon_driver);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("IIO to hwmon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
new file mode 100644
index 0000000..5378fde
--- /dev/null
+++ b/drivers/hwmon/ina209.c
@@ -0,0 +1,626 @@
+/*
+ * Driver for the Texas Instruments / Burr Brown INA209
+ * Bidirectional Current/Power Monitor
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from Ira W. Snyder's original driver submission
+ *	Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca>
+ *	Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Aligned with ina2xx driver
+ *	Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ *	Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.ti.com/lit/gpn/ina209
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* register definitions */
+#define INA209_CONFIGURATION		0x00
+#define INA209_STATUS			0x01
+#define INA209_STATUS_MASK		0x02
+#define INA209_SHUNT_VOLTAGE		0x03
+#define INA209_BUS_VOLTAGE		0x04
+#define INA209_POWER			0x05
+#define INA209_CURRENT			0x06
+#define INA209_SHUNT_VOLTAGE_POS_PEAK	0x07
+#define INA209_SHUNT_VOLTAGE_NEG_PEAK	0x08
+#define INA209_BUS_VOLTAGE_MAX_PEAK	0x09
+#define INA209_BUS_VOLTAGE_MIN_PEAK	0x0a
+#define INA209_POWER_PEAK		0x0b
+#define INA209_SHUNT_VOLTAGE_POS_WARN	0x0c
+#define INA209_SHUNT_VOLTAGE_NEG_WARN	0x0d
+#define INA209_POWER_WARN		0x0e
+#define INA209_BUS_VOLTAGE_OVER_WARN	0x0f
+#define INA209_BUS_VOLTAGE_UNDER_WARN	0x10
+#define INA209_POWER_OVER_LIMIT		0x11
+#define INA209_BUS_VOLTAGE_OVER_LIMIT	0x12
+#define INA209_BUS_VOLTAGE_UNDER_LIMIT	0x13
+#define INA209_CRITICAL_DAC_POS		0x14
+#define INA209_CRITICAL_DAC_NEG		0x15
+#define INA209_CALIBRATION		0x16
+
+#define INA209_REGISTERS		0x17
+
+#define INA209_CONFIG_DEFAULT		0x3c47	/* PGA=8, full range */
+#define INA209_SHUNT_DEFAULT		10000	/* uOhm */
+
+struct ina209_data {
+	struct i2c_client *client;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+
+	u16 regs[INA209_REGISTERS];	/* All chip registers */
+
+	u16 config_orig;		/* Original configuration */
+	u16 calibration_orig;		/* Original calibration */
+	u16 update_interval;
+};
+
+static struct ina209_data *ina209_update_device(struct device *dev)
+{
+	struct ina209_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct ina209_data *ret = data;
+	s32 val;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid ||
+	    time_after(jiffies, data->last_updated + data->update_interval)) {
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			val = i2c_smbus_read_word_swapped(client, i);
+			if (val < 0) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->regs[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/*
+ * Read a value from a device register and convert it to the
+ * appropriate sysfs units
+ */
+static long ina209_from_reg(const u8 reg, const u16 val)
+{
+	switch (reg) {
+	case INA209_SHUNT_VOLTAGE:
+	case INA209_SHUNT_VOLTAGE_POS_PEAK:
+	case INA209_SHUNT_VOLTAGE_NEG_PEAK:
+	case INA209_SHUNT_VOLTAGE_POS_WARN:
+	case INA209_SHUNT_VOLTAGE_NEG_WARN:
+		/* LSB=10 uV. Convert to mV. */
+		return DIV_ROUND_CLOSEST(val, 100);
+
+	case INA209_BUS_VOLTAGE:
+	case INA209_BUS_VOLTAGE_MAX_PEAK:
+	case INA209_BUS_VOLTAGE_MIN_PEAK:
+	case INA209_BUS_VOLTAGE_OVER_WARN:
+	case INA209_BUS_VOLTAGE_UNDER_WARN:
+	case INA209_BUS_VOLTAGE_OVER_LIMIT:
+	case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+		/* LSB=4 mV, last 3 bits unused */
+		return (val >> 3) * 4;
+
+	case INA209_CRITICAL_DAC_POS:
+		/* LSB=1 mV, in the upper 8 bits */
+		return val >> 8;
+
+	case INA209_CRITICAL_DAC_NEG:
+		/* LSB=1 mV, in the upper 8 bits */
+		return -1 * (val >> 8);
+
+	case INA209_POWER:
+	case INA209_POWER_PEAK:
+	case INA209_POWER_WARN:
+	case INA209_POWER_OVER_LIMIT:
+		/* LSB=20 mW. Convert to uW */
+		return val * 20 * 1000L;
+
+	case INA209_CURRENT:
+		/* LSB=1 mA (selected). Is in mA */
+		return val;
+	}
+
+	/* programmer goofed */
+	WARN_ON_ONCE(1);
+	return 0;
+}
+
+/*
+ * Take a value and convert it to register format, clamping the value
+ * to the appropriate range.
+ */
+static int ina209_to_reg(u8 reg, u16 old, long val)
+{
+	switch (reg) {
+	case INA209_SHUNT_VOLTAGE_POS_WARN:
+	case INA209_SHUNT_VOLTAGE_NEG_WARN:
+		/* Limit to +- 320 mV, 10 uV LSB */
+		return clamp_val(val, -320, 320) * 100;
+
+	case INA209_BUS_VOLTAGE_OVER_WARN:
+	case INA209_BUS_VOLTAGE_UNDER_WARN:
+	case INA209_BUS_VOLTAGE_OVER_LIMIT:
+	case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+		/*
+		 * Limit to 0-32000 mV, 4 mV LSB
+		 *
+		 * The last three bits aren't part of the value, but we'll
+		 * preserve them in their original state.
+		 */
+		return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3)
+		  | (old & 0x7);
+
+	case INA209_CRITICAL_DAC_NEG:
+		/*
+		 * Limit to -255-0 mV, 1 mV LSB
+		 * Convert the value to a positive value for the register
+		 *
+		 * The value lives in the top 8 bits only, be careful
+		 * and keep original value of other bits.
+		 */
+		return (clamp_val(-val, 0, 255) << 8) | (old & 0xff);
+
+	case INA209_CRITICAL_DAC_POS:
+		/*
+		 * Limit to 0-255 mV, 1 mV LSB
+		 *
+		 * The value lives in the top 8 bits only, be careful
+		 * and keep original value of other bits.
+		 */
+		return (clamp_val(val, 0, 255) << 8) | (old & 0xff);
+
+	case INA209_POWER_WARN:
+	case INA209_POWER_OVER_LIMIT:
+		/* 20 mW LSB */
+		return DIV_ROUND_CLOSEST(val, 20 * 1000);
+	}
+
+	/* Other registers are read-only, return access error */
+	return -EACCES;
+}
+
+static int ina209_interval_from_reg(u16 reg)
+{
+	return 68 >> (15 - ((reg >> 3) & 0x0f));
+}
+
+static u16 ina209_reg_from_interval(u16 config, long interval)
+{
+	int i, adc;
+
+	if (interval <= 0) {
+		adc = 8;
+	} else {
+		adc = 15;
+		for (i = 34 + 34 / 2; i; i >>= 1) {
+			if (i < interval)
+				break;
+			adc--;
+		}
+	}
+	return (config & 0xf807) | (adc << 3) | (adc << 7);
+}
+
+static ssize_t ina209_set_interval(struct device *dev,
+				   struct device_attribute *da,
+				   const char *buf, size_t count)
+{
+	struct ina209_data *data = ina209_update_device(dev);
+	long val;
+	u16 regval;
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION],
+					  val);
+	i2c_smbus_write_word_swapped(data->client, INA209_CONFIGURATION,
+				     regval);
+	data->regs[INA209_CONFIGURATION] = regval;
+	data->update_interval = ina209_interval_from_reg(regval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_show_interval(struct device *dev,
+				    struct device_attribute *da, char *buf)
+{
+	struct ina209_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
+}
+
+/*
+ * History is reset by writing 1 into bit 0 of the respective peak register.
+ * Since more than one peak register may be affected by the scope of a
+ * reset_history attribute write, use a bit mask in attr->index to identify
+ * which registers are affected.
+ */
+static u16 ina209_reset_history_regs[] = {
+	INA209_SHUNT_VOLTAGE_POS_PEAK,
+	INA209_SHUNT_VOLTAGE_NEG_PEAK,
+	INA209_BUS_VOLTAGE_MAX_PEAK,
+	INA209_BUS_VOLTAGE_MIN_PEAK,
+	INA209_POWER_PEAK
+};
+
+static ssize_t ina209_reset_history(struct device *dev,
+				    struct device_attribute *da,
+				    const char *buf,
+				    size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina209_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u32 mask = attr->index;
+	long val;
+	int i, ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) {
+		if (mask & (1 << i))
+			i2c_smbus_write_word_swapped(client,
+					ina209_reset_history_regs[i], 1);
+	}
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_set_value(struct device *dev,
+				struct device_attribute *da,
+				const char *buf,
+				size_t count)
+{
+	struct ina209_data *data = ina209_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int reg = attr->index;
+	long val;
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	ret = ina209_to_reg(reg, data->regs[reg], val);
+	if (ret < 0) {
+		count = ret;
+		goto abort;
+	}
+	i2c_smbus_write_word_swapped(data->client, reg, ret);
+	data->regs[reg] = ret;
+abort:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_show_value(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina209_data *data = ina209_update_device(dev);
+	long val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = ina209_from_reg(attr->index, data->regs[attr->index]);
+	return snprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t ina209_show_alarm(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina209_data *data = ina209_update_device(dev);
+	const unsigned int mask = attr->index;
+	u16 status;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	status = data->regs[INA209_STATUS];
+
+	/*
+	 * All alarms are in the INA209_STATUS register. To avoid a long
+	 * switch statement, the mask is passed in attr->index
+	 */
+	return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
+}
+
+/* Shunt voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE_POS_PEAK);
+static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE_NEG_PEAK);
+static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, (1 << 0) | (1 << 1));
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN);
+static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_CRITICAL_DAC_POS);
+static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_CRITICAL_DAC_NEG);
+
+static SENSOR_DEVICE_ATTR(in0_min_alarm,  S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 11);
+static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 12);
+static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 6);
+static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 7);
+
+/* Bus voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE_MAX_PEAK);
+static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE_MIN_PEAK);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, (1 << 2) | (1 << 3));
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN);
+static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT);
+static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 14);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 15);
+static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 9);
+static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 10);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_POWER);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value,
+			  NULL, INA209_POWER_PEAK);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, 1 << 4);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_POWER_WARN);
+static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_POWER_OVER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 13);
+static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 8);
+
+/* Current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_CURRENT);
+
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+			  ina209_show_interval, ina209_set_interval, 0);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ina209_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_input_highest.dev_attr.attr,
+	&sensor_dev_attr_in0_input_lowest.dev_attr.attr,
+	&sensor_dev_attr_in0_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_max.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input_highest.dev_attr.attr,
+	&sensor_dev_attr_in1_input_lowest.dev_attr.attr,
+	&sensor_dev_attr_in1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_max.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_input_highest.dev_attr.attr,
+	&sensor_dev_attr_power1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_power1_max.dev_attr.attr,
+	&sensor_dev_attr_power1_crit.dev_attr.attr,
+	&sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_power1_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+
+	&sensor_dev_attr_update_interval.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ina209);
+
+static void ina209_restore_conf(struct i2c_client *client,
+				struct ina209_data *data)
+{
+	/* Restore initial configuration */
+	i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+				     data->config_orig);
+	i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+				     data->calibration_orig);
+}
+
+static int ina209_init_client(struct i2c_client *client,
+			      struct ina209_data *data)
+{
+	struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
+	u32 shunt;
+	int reg;
+
+	reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION);
+	if (reg < 0)
+		return reg;
+	data->calibration_orig = reg;
+
+	reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION);
+	if (reg < 0)
+		return reg;
+	data->config_orig = reg;
+
+	if (pdata) {
+		if (pdata->shunt_uohms <= 0)
+			return -EINVAL;
+		shunt = pdata->shunt_uohms;
+	} else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor",
+					 &shunt)) {
+		if (shunt == 0)
+			return -EINVAL;
+	} else {
+		shunt = data->calibration_orig ?
+		  40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT;
+	}
+
+	i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+				     INA209_CONFIG_DEFAULT);
+	data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT);
+
+	/*
+	 * Calibrate current LSB to 1mA. Shunt is in uOhms.
+	 * See equation 13 in datasheet.
+	 */
+	i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+				     clamp_val(40960000 / shunt, 1, 65535));
+
+	/* Clear status register */
+	i2c_smbus_read_word_swapped(client, INA209_STATUS);
+
+	return 0;
+}
+
+static int ina209_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct ina209_data *data;
+	struct device *hwmon_dev;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	ret = ina209_init_client(client, data);
+	if (ret)
+		return ret;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name,
+							   data, ina209_groups);
+	if (IS_ERR(hwmon_dev)) {
+		ret = PTR_ERR(hwmon_dev);
+		goto out_restore_conf;
+	}
+
+	return 0;
+
+out_restore_conf:
+	ina209_restore_conf(client, data);
+	return ret;
+}
+
+static int ina209_remove(struct i2c_client *client)
+{
+	struct ina209_data *data = i2c_get_clientdata(client);
+
+	ina209_restore_conf(client, data);
+
+	return 0;
+}
+
+static const struct i2c_device_id ina209_id[] = {
+	{ "ina209", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ina209_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ina209_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "ina209",
+	},
+	.probe		= ina209_probe,
+	.remove		= ina209_remove,
+	.id_table	= ina209_id,
+};
+
+module_i2c_driver(ina209_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("INA209 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 0000000..b24f1d3
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
@@ -0,0 +1,502 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * INA219:
+ * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina219
+ *
+ * INA220:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina220
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * INA230:
+ * Bi-directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina230
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#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/jiffies.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/util_macros.h>
+#include <linux/regmap.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* common register definitions */
+#define INA2XX_CONFIG			0x00
+#define INA2XX_SHUNT_VOLTAGE		0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE		0x02 /* readonly */
+#define INA2XX_POWER			0x03 /* readonly */
+#define INA2XX_CURRENT			0x04 /* readonly */
+#define INA2XX_CALIBRATION		0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE		0x06
+#define INA226_ALERT_LIMIT		0x07
+#define INA226_DIE_ID			0xFF
+
+/* register count */
+#define INA219_REGISTERS		6
+#define INA226_REGISTERS		8
+
+#define INA2XX_MAX_REGISTERS		8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT		0x399F	/* PGA=8 */
+#define INA226_CONFIG_DEFAULT		0x4527	/* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE		15
+#define INA2XX_MAX_DELAY		69 /* worst case delay in ms */
+
+#define INA2XX_RSHUNT_DEFAULT		10000
+
+/* bit mask for reading the averaging setting in the configuration register */
+#define INA226_AVG_RD_MASK		0x0E00
+
+#define INA226_READ_AVG(reg)		(((reg) & INA226_AVG_RD_MASK) >> 9)
+#define INA226_SHIFT_AVG(val)		((val) << 9)
+
+/* common attrs, ina226 attrs and NULL */
+#define INA2XX_MAX_ATTRIBUTE_GROUPS	3
+
+/*
+ * Both bus voltage and shunt voltage conversion times for ina226 are set
+ * to 0b0100 on POR, which translates to 2200 microseconds in total.
+ */
+#define INA226_TOTAL_CONV_TIME_DEFAULT	2200
+
+static struct regmap_config ina2xx_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+};
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_config {
+	u16 config_default;
+	int calibration_factor;
+	int registers;
+	int shunt_div;
+	int bus_voltage_shift;
+	int bus_voltage_lsb;	/* uV */
+	int power_lsb;		/* uW */
+};
+
+struct ina2xx_data {
+	const struct ina2xx_config *config;
+
+	long rshunt;
+	struct mutex config_lock;
+	struct regmap *regmap;
+
+	const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
+};
+
+static const struct ina2xx_config ina2xx_config[] = {
+	[ina219] = {
+		.config_default = INA219_CONFIG_DEFAULT,
+		.calibration_factor = 40960000,
+		.registers = INA219_REGISTERS,
+		.shunt_div = 100,
+		.bus_voltage_shift = 3,
+		.bus_voltage_lsb = 4000,
+		.power_lsb = 20000,
+	},
+	[ina226] = {
+		.config_default = INA226_CONFIG_DEFAULT,
+		.calibration_factor = 5120000,
+		.registers = INA226_REGISTERS,
+		.shunt_div = 400,
+		.bus_voltage_shift = 0,
+		.bus_voltage_lsb = 1250,
+		.power_lsb = 25000,
+	},
+};
+
+/*
+ * Available averaging rates for ina226. The indices correspond with
+ * the bit values expected by the chip (according to the ina226 datasheet,
+ * table 3 AVG bit settings, found at
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ */
+static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
+
+static int ina226_reg_to_interval(u16 config)
+{
+	int avg = ina226_avg_tab[INA226_READ_AVG(config)];
+
+	/*
+	 * Multiply the total conversion time by the number of averages.
+	 * Return the result in milliseconds.
+	 */
+	return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000);
+}
+
+/*
+ * Return the new, shifted AVG field value of CONFIG register,
+ * to use with regmap_update_bits
+ */
+static u16 ina226_interval_to_reg(int interval)
+{
+	int avg, avg_bits;
+
+	avg = DIV_ROUND_CLOSEST(interval * 1000,
+				INA226_TOTAL_CONV_TIME_DEFAULT);
+	avg_bits = find_closest(avg, ina226_avg_tab,
+				ARRAY_SIZE(ina226_avg_tab));
+
+	return INA226_SHIFT_AVG(avg_bits);
+}
+
+static int ina2xx_calibrate(struct ina2xx_data *data)
+{
+	u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
+				    data->rshunt);
+
+	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
+}
+
+/*
+ * Initialize the configuration and calibration registers.
+ */
+static int ina2xx_init(struct ina2xx_data *data)
+{
+	int ret = regmap_write(data->regmap, INA2XX_CONFIG,
+			       data->config->config_default);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Set current LSB to 1mA, shunt is in uOhms
+	 * (equation 13 in datasheet).
+	 */
+	return ina2xx_calibrate(data);
+}
+
+static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval)
+{
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+	int ret, retry;
+
+	dev_dbg(dev, "Starting register %d read\n", reg);
+
+	for (retry = 5; retry; retry--) {
+
+		ret = regmap_read(data->regmap, reg, regval);
+		if (ret < 0)
+			return ret;
+
+		dev_dbg(dev, "read %d, val = 0x%04x\n", reg, *regval);
+
+		/*
+		 * If the current value in the calibration register is 0, the
+		 * power and current registers will also remain at 0. In case
+		 * the chip has been reset let's check the calibration
+		 * register and reinitialize if needed.
+		 * We do that extra read of the calibration register if there
+		 * is some hint of a chip reset.
+		 */
+		if (*regval == 0) {
+			unsigned int cal;
+
+			ret = regmap_read(data->regmap, INA2XX_CALIBRATION,
+					  &cal);
+			if (ret < 0)
+				return ret;
+
+			if (cal == 0) {
+				dev_warn(dev, "chip not calibrated, reinitializing\n");
+
+				ret = ina2xx_init(data);
+				if (ret < 0)
+					return ret;
+				/*
+				 * Let's make sure the power and current
+				 * registers have been updated before trying
+				 * again.
+				 */
+				msleep(INA2XX_MAX_DELAY);
+				continue;
+			}
+		}
+		return 0;
+	}
+
+	/*
+	 * If we're here then although all write operations succeeded, the
+	 * chip still returns 0 in the calibration register. Nothing more we
+	 * can do here.
+	 */
+	dev_err(dev, "unable to reinitialize the chip\n");
+	return -ENODEV;
+}
+
+static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
+			    unsigned int regval)
+{
+	int val;
+
+	switch (reg) {
+	case INA2XX_SHUNT_VOLTAGE:
+		/* signed register */
+		val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div);
+		break;
+	case INA2XX_BUS_VOLTAGE:
+		val = (regval >> data->config->bus_voltage_shift)
+		  * data->config->bus_voltage_lsb;
+		val = DIV_ROUND_CLOSEST(val, 1000);
+		break;
+	case INA2XX_POWER:
+		val = regval * data->config->power_lsb;
+		break;
+	case INA2XX_CURRENT:
+		/* signed register, LSB=1mA (selected), in mA */
+		val = (s16)regval;
+		break;
+	case INA2XX_CALIBRATION:
+		val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
+					regval);
+		break;
+	default:
+		/* programmer goofed */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static ssize_t ina2xx_show_value(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+	unsigned int regval;
+
+	int err = ina2xx_read_reg(dev, attr->index, &regval);
+
+	if (err < 0)
+		return err;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			ina2xx_get_value(data, attr->index, regval));
+}
+
+static ssize_t ina2xx_set_shunt(struct device *dev,
+				struct device_attribute *da,
+				const char *buf, size_t count)
+{
+	unsigned long val;
+	int status;
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+
+	status = kstrtoul(buf, 10, &val);
+	if (status < 0)
+		return status;
+
+	if (val == 0 ||
+	    /* Values greater than the calibration factor make no sense. */
+	    val > data->config->calibration_factor)
+		return -EINVAL;
+
+	mutex_lock(&data->config_lock);
+	data->rshunt = val;
+	status = ina2xx_calibrate(data);
+	mutex_unlock(&data->config_lock);
+	if (status < 0)
+		return status;
+
+	return count;
+}
+
+static ssize_t ina226_set_interval(struct device *dev,
+				   struct device_attribute *da,
+				   const char *buf, size_t count)
+{
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int status;
+
+	status = kstrtoul(buf, 10, &val);
+	if (status < 0)
+		return status;
+
+	if (val > INT_MAX || val == 0)
+		return -EINVAL;
+
+	status = regmap_update_bits(data->regmap, INA2XX_CONFIG,
+				    INA226_AVG_RD_MASK,
+				    ina226_interval_to_reg(val));
+	if (status < 0)
+		return status;
+
+	return count;
+}
+
+static ssize_t ina226_show_interval(struct device *dev,
+				    struct device_attribute *da, char *buf)
+{
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+	int status;
+	unsigned int regval;
+
+	status = regmap_read(data->regmap, INA2XX_CONFIG, &regval);
+	if (status)
+		return status;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));
+}
+
+/* shunt voltage */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
+			  INA2XX_SHUNT_VOLTAGE);
+
+/* bus voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
+			  INA2XX_BUS_VOLTAGE);
+
+/* calculated current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
+			  INA2XX_CURRENT);
+
+/* calculated power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
+			  INA2XX_POWER);
+
+/* shunt resistance */
+static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
+			  ina2xx_show_value, ina2xx_set_shunt,
+			  INA2XX_CALIBRATION);
+
+/* update interval (ina226 only) */
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+			  ina226_show_interval, ina226_set_interval, 0);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	&sensor_dev_attr_shunt_resistor.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+	.attrs = ina2xx_attrs,
+};
+
+static struct attribute *ina226_attrs[] = {
+	&sensor_dev_attr_update_interval.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ina226_group = {
+	.attrs = ina226_attrs,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct ina2xx_data *data;
+	struct device *hwmon_dev;
+	u32 val;
+	int ret, group = 0;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* set the device type */
+	data->config = &ina2xx_config[id->driver_data];
+
+	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
+		struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
+
+		if (pdata)
+			val = pdata->shunt_uohms;
+		else
+			val = INA2XX_RSHUNT_DEFAULT;
+	}
+
+	if (val <= 0 || val > data->config->calibration_factor)
+		return -ENODEV;
+
+	data->rshunt = val;
+
+	ina2xx_regmap_config.max_register = data->config->registers;
+
+	data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		dev_err(dev, "failed to allocate register map\n");
+		return PTR_ERR(data->regmap);
+	}
+
+	ret = ina2xx_init(data);
+	if (ret < 0) {
+		dev_err(dev, "error configuring the device: %d\n", ret);
+		return -ENODEV;
+	}
+
+	mutex_init(&data->config_lock);
+
+	data->groups[group++] = &ina2xx_group;
+	if (id->driver_data == ina226)
+		data->groups[group++] = &ina226_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
+		 id->name, data->rshunt);
+
+	return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+	{ "ina219", ina219 },
+	{ "ina220", ina219 },
+	{ "ina226", ina226 },
+	{ "ina230", ina226 },
+	{ "ina231", ina226 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+	.driver = {
+		.name	= "ina2xx",
+	},
+	.probe		= ina2xx_probe,
+	.id_table	= ina2xx_id,
+};
+
+module_i2c_driver(ina2xx_driver);
+
+MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
new file mode 100644
index 0000000..1896e26
--- /dev/null
+++ b/drivers/hwmon/it87.c
@@ -0,0 +1,2860 @@
+/*
+ *  it87.c - Part of lm_sensors, Linux kernel modules for hardware
+ *           monitoring.
+ *
+ *  The IT8705F is an LPC-based Super I/O part that contains UARTs, a
+ *  parallel port, an IR port, a MIDI port, a floppy controller, etc., in
+ *  addition to an Environment Controller (Enhanced Hardware Monitor and
+ *  Fan Controller)
+ *
+ *  This driver supports only the Environment Controller in the IT8705F and
+ *  similar parts.  The other devices are supported by different drivers.
+ *
+ *  Supports: IT8603E  Super I/O chip w/LPC interface
+ *            IT8620E  Super I/O chip w/LPC interface
+ *            IT8623E  Super I/O chip w/LPC interface
+ *            IT8705F  Super I/O chip w/LPC interface
+ *            IT8712F  Super I/O chip w/LPC interface
+ *            IT8716F  Super I/O chip w/LPC interface
+ *            IT8718F  Super I/O chip w/LPC interface
+ *            IT8720F  Super I/O chip w/LPC interface
+ *            IT8721F  Super I/O chip w/LPC interface
+ *            IT8726F  Super I/O chip w/LPC interface
+ *            IT8728F  Super I/O chip w/LPC interface
+ *            IT8732F  Super I/O chip w/LPC interface
+ *            IT8758E  Super I/O chip w/LPC interface
+ *            IT8771E  Super I/O chip w/LPC interface
+ *            IT8772E  Super I/O chip w/LPC interface
+ *            IT8781F  Super I/O chip w/LPC interface
+ *            IT8782F  Super I/O chip w/LPC interface
+ *            IT8783E/F Super I/O chip w/LPC interface
+ *            IT8786E  Super I/O chip w/LPC interface
+ *            IT8790E  Super I/O chip w/LPC interface
+ *            Sis950   A clone of the IT8705F
+ *
+ *  Copyright (C) 2001 Chris Gauthron
+ *  Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.de>
+ *
+ *  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.
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+#define DRVNAME "it87"
+
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
+	     it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603,
+	     it8620 };
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define	REG	0x2e	/* The register to read/write */
+#define	DEV	0x07	/* Register: Logical device select */
+#define	VAL	0x2f	/* The value to read/write */
+#define PME	0x04	/* The device with the fan registers in it */
+
+/* The device with the IT8718F/IT8720F VID value in it */
+#define GPIO	0x07
+
+#define	DEVID	0x20	/* Register: Device ID */
+#define	DEVREV	0x22	/* Register: Device Revision */
+
+static inline int superio_inb(int reg)
+{
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+static inline void superio_outb(int reg, int val)
+{
+	outb(reg, REG);
+	outb(val, VAL);
+}
+
+static int superio_inw(int reg)
+{
+	int val;
+	outb(reg++, REG);
+	val = inb(VAL) << 8;
+	outb(reg, REG);
+	val |= inb(VAL);
+	return val;
+}
+
+static inline void superio_select(int ldn)
+{
+	outb(DEV, REG);
+	outb(ldn, VAL);
+}
+
+static inline int superio_enter(void)
+{
+	/*
+	 * Try to reserve REG and REG + 1 for exclusive access.
+	 */
+	if (!request_muxed_region(REG, 2, DRVNAME))
+		return -EBUSY;
+
+	outb(0x87, REG);
+	outb(0x01, REG);
+	outb(0x55, REG);
+	outb(0x55, REG);
+	return 0;
+}
+
+static inline void superio_exit(void)
+{
+	outb(0x02, REG);
+	outb(0x02, VAL);
+	release_region(REG, 2);
+}
+
+/* Logical device 4 registers */
+#define IT8712F_DEVID 0x8712
+#define IT8705F_DEVID 0x8705
+#define IT8716F_DEVID 0x8716
+#define IT8718F_DEVID 0x8718
+#define IT8720F_DEVID 0x8720
+#define IT8721F_DEVID 0x8721
+#define IT8726F_DEVID 0x8726
+#define IT8728F_DEVID 0x8728
+#define IT8732F_DEVID 0x8732
+#define IT8771E_DEVID 0x8771
+#define IT8772E_DEVID 0x8772
+#define IT8781F_DEVID 0x8781
+#define IT8782F_DEVID 0x8782
+#define IT8783E_DEVID 0x8783
+#define IT8786E_DEVID 0x8786
+#define IT8790E_DEVID 0x8790
+#define IT8603E_DEVID 0x8603
+#define IT8620E_DEVID 0x8620
+#define IT8623E_DEVID 0x8623
+#define IT87_ACT_REG  0x30
+#define IT87_BASE_REG 0x60
+
+/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO1_REG	0x25
+#define IT87_SIO_GPIO2_REG	0x26
+#define IT87_SIO_GPIO3_REG	0x27
+#define IT87_SIO_GPIO5_REG	0x29
+#define IT87_SIO_PINX1_REG	0x2a	/* Pin selection */
+#define IT87_SIO_PINX2_REG	0x2c	/* Pin selection */
+#define IT87_SIO_SPI_REG	0xef	/* SPI function pin select */
+#define IT87_SIO_VID_REG	0xfc	/* VID value */
+#define IT87_SIO_BEEP_PIN_REG	0xf6	/* Beep pin mapping */
+
+/* Update battery voltage after every reading if true */
+static bool update_vbat;
+
+/* Not all BIOSes properly configure the PWM registers */
+static bool fix_pwm_polarity;
+
+/* Many IT87 constants specified below */
+
+/* Length of ISA address segment */
+#define IT87_EXTENT 8
+
+/* Length of ISA address segment for Environmental Controller */
+#define IT87_EC_EXTENT 2
+
+/* Offset of EC registers from ISA base address */
+#define IT87_EC_OFFSET 5
+
+/* Where are the ISA address/data registers relative to the EC base address */
+#define IT87_ADDR_REG_OFFSET 0
+#define IT87_DATA_REG_OFFSET 1
+
+/*----- The IT87 registers -----*/
+
+#define IT87_REG_CONFIG        0x00
+
+#define IT87_REG_ALARM1        0x01
+#define IT87_REG_ALARM2        0x02
+#define IT87_REG_ALARM3        0x03
+
+/*
+ * The IT8718F and IT8720F have the VID value in a different register, in
+ * Super-I/O configuration space.
+ */
+#define IT87_REG_VID           0x0a
+/*
+ * The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
+ * for fan divisors. Later IT8712F revisions must use 16-bit tachometer
+ * mode.
+ */
+#define IT87_REG_FAN_DIV       0x0b
+#define IT87_REG_FAN_16BIT     0x0c
+
+/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
+
+static const u8 IT87_REG_FAN[]         = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
+static const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
+static const u8 IT87_REG_FANX[]        = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d };
+static const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f };
+static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
+
+#define IT87_REG_FAN_MAIN_CTRL 0x13
+#define IT87_REG_FAN_CTL       0x14
+#define IT87_REG_PWM(nr)       (0x15 + (nr))
+#define IT87_REG_PWM_DUTY(nr)  (0x63 + (nr) * 8)
+
+#define IT87_REG_VIN(nr)       (0x20 + (nr))
+#define IT87_REG_TEMP(nr)      (0x29 + (nr))
+
+#define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)
+#define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)
+#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
+#define IT87_REG_TEMP_LOW(nr)  (0x41 + (nr) * 2)
+
+#define IT87_REG_VIN_ENABLE    0x50
+#define IT87_REG_TEMP_ENABLE   0x51
+#define IT87_REG_TEMP_EXTRA    0x55
+#define IT87_REG_BEEP_ENABLE   0x5c
+
+#define IT87_REG_CHIPID        0x58
+
+#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
+#define IT87_REG_AUTO_PWM(nr, i)  (0x65 + (nr) * 8 + (i))
+
+struct it87_devices {
+	const char *name;
+	const char * const suffix;
+	u16 features;
+	u8 peci_mask;
+	u8 old_peci_mask;
+};
+
+#define FEAT_12MV_ADC		(1 << 0)
+#define FEAT_NEWER_AUTOPWM	(1 << 1)
+#define FEAT_OLD_AUTOPWM	(1 << 2)
+#define FEAT_16BIT_FANS		(1 << 3)
+#define FEAT_TEMP_OFFSET	(1 << 4)
+#define FEAT_TEMP_PECI		(1 << 5)
+#define FEAT_TEMP_OLD_PECI	(1 << 6)
+#define FEAT_FAN16_CONFIG	(1 << 7)	/* Need to enable 16-bit fans */
+#define FEAT_FIVE_FANS		(1 << 8)	/* Supports five fans */
+#define FEAT_VID		(1 << 9)	/* Set if chip supports VID */
+#define FEAT_IN7_INTERNAL	(1 << 10)	/* Set if in7 is internal */
+#define FEAT_SIX_FANS		(1 << 11)	/* Supports six fans */
+#define FEAT_10_9MV_ADC		(1 << 12)
+
+static const struct it87_devices it87_devices[] = {
+	[it87] = {
+		.name = "it87",
+		.suffix = "F",
+		.features = FEAT_OLD_AUTOPWM,	/* may need to overwrite */
+	},
+	[it8712] = {
+		.name = "it8712",
+		.suffix = "F",
+		.features = FEAT_OLD_AUTOPWM | FEAT_VID,
+						/* may need to overwrite */
+	},
+	[it8716] = {
+		.name = "it8716",
+		.suffix = "F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+	},
+	[it8718] = {
+		.name = "it8718",
+		.suffix = "F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+		.old_peci_mask = 0x4,
+	},
+	[it8720] = {
+		.name = "it8720",
+		.suffix = "F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+		.old_peci_mask = 0x4,
+	},
+	[it8721] = {
+		.name = "it8721",
+		.suffix = "F",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x05,
+		.old_peci_mask = 0x02,	/* Actually reports PCH */
+	},
+	[it8728] = {
+		.name = "it8728",
+		.suffix = "F",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
+		  | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+	},
+	[it8732] = {
+		.name = "it8732",
+		.suffix = "F",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+		.old_peci_mask = 0x02,	/* Actually reports PCH */
+	},
+	[it8771] = {
+		.name = "it8771",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+				/* PECI: guesswork */
+				/* 12mV ADC (OHM) */
+				/* 16 bit fans (OHM) */
+				/* three fans, always 16 bit (guesswork) */
+		.peci_mask = 0x07,
+	},
+	[it8772] = {
+		.name = "it8772",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+				/* PECI (coreboot) */
+				/* 12mV ADC (HWSensors4, OHM) */
+				/* 16 bit fans (HWSensors4, OHM) */
+				/* three fans, always 16 bit (datasheet) */
+		.peci_mask = 0x07,
+	},
+	[it8781] = {
+		.name = "it8781",
+		.suffix = "F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+		.old_peci_mask = 0x4,
+	},
+	[it8782] = {
+		.name = "it8782",
+		.suffix = "F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+		.old_peci_mask = 0x4,
+	},
+	[it8783] = {
+		.name = "it8783",
+		.suffix = "E/F",
+		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+		.old_peci_mask = 0x4,
+	},
+	[it8786] = {
+		.name = "it8786",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+	},
+	[it8790] = {
+		.name = "it8790",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+	},
+	[it8603] = {
+		.name = "it8603",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+	},
+	[it8620] = {
+		.name = "it8620",
+		.suffix = "E",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
+		  | FEAT_IN7_INTERNAL,
+		.peci_mask = 0x07,
+	},
+};
+
+#define has_16bit_fans(data)	((data)->features & FEAT_16BIT_FANS)
+#define has_12mv_adc(data)	((data)->features & FEAT_12MV_ADC)
+#define has_10_9mv_adc(data)	((data)->features & FEAT_10_9MV_ADC)
+#define has_newer_autopwm(data)	((data)->features & FEAT_NEWER_AUTOPWM)
+#define has_old_autopwm(data)	((data)->features & FEAT_OLD_AUTOPWM)
+#define has_temp_offset(data)	((data)->features & FEAT_TEMP_OFFSET)
+#define has_temp_peci(data, nr)	(((data)->features & FEAT_TEMP_PECI) && \
+				 ((data)->peci_mask & (1 << nr)))
+#define has_temp_old_peci(data, nr) \
+				(((data)->features & FEAT_TEMP_OLD_PECI) && \
+				 ((data)->old_peci_mask & (1 << nr)))
+#define has_fan16_config(data)	((data)->features & FEAT_FAN16_CONFIG)
+#define has_five_fans(data)	((data)->features & (FEAT_FIVE_FANS | \
+						     FEAT_SIX_FANS))
+#define has_vid(data)		((data)->features & FEAT_VID)
+#define has_in7_internal(data)	((data)->features & FEAT_IN7_INTERNAL)
+#define has_six_fans(data)	((data)->features & FEAT_SIX_FANS)
+
+struct it87_sio_data {
+	enum chips type;
+	/* Values read from Super-I/O config space */
+	u8 revision;
+	u8 vid_value;
+	u8 beep_pin;
+	u8 internal;	/* Internal sensors can be labeled */
+	/* Features skipped based on config or DMI */
+	u16 skip_in;
+	u8 skip_vid;
+	u8 skip_fan;
+	u8 skip_pwm;
+	u8 skip_temp;
+};
+
+/*
+ * For each registered chip, we need to keep some data in memory.
+ * The structure is dynamically allocated.
+ */
+struct it87_data {
+	struct device *hwmon_dev;
+	enum chips type;
+	u16 features;
+	u8 peci_mask;
+	u8 old_peci_mask;
+
+	unsigned short addr;
+	const char *name;
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u16 in_scaled;		/* Internal voltage sensors are scaled */
+	u8 in[10][3];		/* [nr][0]=in, [1]=min, [2]=max */
+	u8 has_fan;		/* Bitfield, fans enabled */
+	u16 fan[6][2];		/* Register values, [nr][0]=fan, [1]=min */
+	u8 has_temp;		/* Bitfield, temp sensors enabled */
+	s8 temp[3][4];		/* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
+	u8 sensor;		/* Register value (IT87_REG_TEMP_ENABLE) */
+	u8 extra;		/* Register value (IT87_REG_TEMP_EXTRA) */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 vid;			/* Register encoding, combined */
+	u8 vrm;
+	u32 alarms;		/* Register encoding, combined */
+	u8 beeps;		/* Register encoding */
+	u8 fan_main_ctrl;	/* Register value */
+	u8 fan_ctl;		/* Register value */
+
+	/*
+	 * The following 3 arrays correspond to the same registers up to
+	 * the IT8720F. The meaning of bits 6-0 depends on the value of bit
+	 * 7, and we want to preserve settings on mode changes, so we have
+	 * to track all values separately.
+	 * Starting with the IT8721F, the manual PWM duty cycles are stored
+	 * in separate registers (8-bit values), so the separate tracking
+	 * is no longer needed, but it is still done to keep the driver
+	 * simple.
+	 */
+	u8 pwm_ctrl[3];		/* Register value */
+	u8 pwm_duty[3];		/* Manual PWM value set by user */
+	u8 pwm_temp_map[3];	/* PWM to temp. chan. mapping (bits 1-0) */
+
+	/* Automatic fan speed control registers */
+	u8 auto_pwm[3][4];	/* [nr][3] is hard-coded */
+	s8 auto_temp[3][5];	/* [nr][0] is point1_temp_hyst */
+};
+
+static int adc_lsb(const struct it87_data *data, int nr)
+{
+	int lsb;
+
+	if (has_12mv_adc(data))
+		lsb = 120;
+	else if (has_10_9mv_adc(data))
+		lsb = 109;
+	else
+		lsb = 160;
+	if (data->in_scaled & (1 << nr))
+		lsb <<= 1;
+	return lsb;
+}
+
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+{
+	val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr));
+	return clamp_val(val, 0, 255);
+}
+
+static int in_from_reg(const struct it87_data *data, int nr, int val)
+{
+	return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10);
+}
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static inline u16 FAN16_TO_REG(long rpm)
+{
+	if (rpm == 0)
+		return 0xffff;
+	return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+}
+
+#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
+				1350000 / ((val) * (div)))
+/* The divider is fixed to 2 in 16-bit mode */
+#define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
+			     1350000 / ((val) * 2))
+
+#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
+				    ((val) + 500) / 1000), -128, 127))
+#define TEMP_FROM_REG(val) ((val) * 1000)
+
+static u8 pwm_to_reg(const struct it87_data *data, long val)
+{
+	if (has_newer_autopwm(data))
+		return val;
+	else
+		return val >> 1;
+}
+
+static int pwm_from_reg(const struct it87_data *data, u8 reg)
+{
+	if (has_newer_autopwm(data))
+		return reg;
+	else
+		return (reg & 0x7f) << 1;
+}
+
+
+static int DIV_TO_REG(int val)
+{
+	int answer = 0;
+	while (answer < 7 && (val >>= 1))
+		answer++;
+	return answer;
+}
+#define DIV_FROM_REG(val) (1 << (val))
+
+/*
+ * PWM base frequencies. The frequency has to be divided by either 128 or 256,
+ * depending on the chip type, to calculate the actual PWM frequency.
+ *
+ * Some of the chip datasheets suggest a base frequency of 51 kHz instead
+ * of 750 kHz for the slowest base frequency, resulting in a PWM frequency
+ * of 200 Hz. Sometimes both PWM frequency select registers are affected,
+ * sometimes just one. It is unknown if this is a datasheet error or real,
+ * so this is ignored for now.
+ */
+static const unsigned int pwm_freq[8] = {
+	48000000,
+	24000000,
+	12000000,
+	8000000,
+	6000000,
+	3000000,
+	1500000,
+	750000,
+};
+
+static int it87_probe(struct platform_device *pdev);
+static int it87_remove(struct platform_device *pdev);
+
+static int it87_read_value(struct it87_data *data, u8 reg);
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
+static struct it87_data *it87_update_device(struct device *dev);
+static int it87_check_pwm(struct device *dev);
+static void it87_init_device(struct platform_device *pdev);
+
+
+static struct platform_driver it87_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe	= it87_probe,
+	.remove	= it87_remove,
+};
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->in[nr][index] = in_to_reg(data, nr, val);
+	it87_write_value(data,
+			 index == 1 ? IT87_REG_VIN_MIN(nr)
+				    : IT87_REG_VIN_MAX(nr),
+			 data->in[nr][index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    6, 2);
+
+static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in,
+			    7, 1);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
+			    7, 2);
+
+static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
+static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);
+
+/* 3 temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	struct it87_data *data = it87_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+	u8 reg, regval;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	switch (index) {
+	default:
+	case 1:
+		reg = IT87_REG_TEMP_LOW(nr);
+		break;
+	case 2:
+		reg = IT87_REG_TEMP_HIGH(nr);
+		break;
+	case 3:
+		regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+		if (!(regval & 0x80)) {
+			regval |= 0x80;
+			it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
+		}
+		data->valid = 0;
+		reg = IT87_REG_TEMP_OFFSET[nr];
+		break;
+	}
+
+	data->temp[nr][index] = TEMP_TO_REG(val);
+	it87_write_value(data, reg, data->temp[nr][index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, 0, 3);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, 1, 3);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
+			    set_temp, 2, 3);
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct it87_data *data = it87_update_device(dev);
+	u8 reg = data->sensor;	    /* In case value is updated while used */
+	u8 extra = data->extra;
+
+	if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1))
+	    || (has_temp_old_peci(data, nr) && (extra & 0x80)))
+		return sprintf(buf, "6\n");  /* Intel PECI */
+	if (reg & (1 << nr))
+		return sprintf(buf, "3\n");  /* thermal diode */
+	if (reg & (8 << nr))
+		return sprintf(buf, "4\n");  /* thermistor */
+	return sprintf(buf, "0\n");      /* disabled */
+}
+
+static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+	u8 reg, extra;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+	reg &= ~(1 << nr);
+	reg &= ~(8 << nr);
+	if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6))
+		reg &= 0x3f;
+	extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+	if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6))
+		extra &= 0x7f;
+	if (val == 2) {	/* backwards compatibility */
+		dev_warn(dev,
+			 "Sensor type 2 is deprecated, please use 4 instead\n");
+		val = 4;
+	}
+	/* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */
+	if (val == 3)
+		reg |= 1 << nr;
+	else if (val == 4)
+		reg |= 8 << nr;
+	else if (has_temp_peci(data, nr) && val == 6)
+		reg |= (nr + 1) << 6;
+	else if (has_temp_old_peci(data, nr) && val == 6)
+		extra |= 0x80;
+	else if (val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->sensor = reg;
+	data->extra = extra;
+	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
+	if (has_temp_old_peci(data, nr))
+		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
+	data->valid = 0;	/* Force cache refresh */
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+			  set_temp_type, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+			  set_temp_type, 1);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+			  set_temp_type, 2);
+
+/* 3 Fans */
+
+static int pwm_mode(const struct it87_data *data, int nr)
+{
+	int ctrl = data->fan_main_ctrl & (1 << nr);
+
+	if (ctrl == 0 && data->type != it8603)		/* Full speed */
+		return 0;
+	if (data->pwm_ctrl[nr] & 0x80)			/* Automatic mode */
+		return 2;
+	else						/* Manual mode */
+		return 1;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	int speed;
+	struct it87_data *data = it87_update_device(dev);
+
+	speed = has_16bit_fans(data) ?
+		FAN16_FROM_REG(data->fan[nr][index]) :
+		FAN_FROM_REG(data->fan[nr][index],
+			     DIV_FROM_REG(data->fan_div[nr]));
+	return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+static ssize_t show_pwm_enable(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%d\n", pwm_mode(data, nr));
+}
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       pwm_from_reg(data, data->pwm_duty[nr]));
+}
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct it87_data *data = it87_update_device(dev);
+	int index = (data->fan_ctl >> 4) & 0x07;
+	unsigned int freq;
+
+	freq = pwm_freq[index] / (has_newer_autopwm(data) ? 256 : 128);
+
+	return sprintf(buf, "%u\n", freq);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+	u8 reg;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	if (has_16bit_fans(data)) {
+		data->fan[nr][index] = FAN16_TO_REG(val);
+		it87_write_value(data, IT87_REG_FAN_MIN[nr],
+				 data->fan[nr][index] & 0xff);
+		it87_write_value(data, IT87_REG_FANX_MIN[nr],
+				 data->fan[nr][index] >> 8);
+	} else {
+		reg = it87_read_value(data, IT87_REG_FAN_DIV);
+		switch (nr) {
+		case 0:
+			data->fan_div[nr] = reg & 0x07;
+			break;
+		case 1:
+			data->fan_div[nr] = (reg >> 3) & 0x07;
+			break;
+		case 2:
+			data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
+			break;
+		}
+		data->fan[nr][index] =
+		  FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+		it87_write_value(data, IT87_REG_FAN_MIN[nr],
+				 data->fan[nr][index]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int min;
+	u8 old;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	old = it87_read_value(data, IT87_REG_FAN_DIV);
+
+	/* Save fan min limit */
+	min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr]));
+
+	switch (nr) {
+	case 0:
+	case 1:
+		data->fan_div[nr] = DIV_TO_REG(val);
+		break;
+	case 2:
+		if (val < 8)
+			data->fan_div[nr] = 1;
+		else
+			data->fan_div[nr] = 3;
+	}
+	val = old & 0x80;
+	val |= (data->fan_div[0] & 0x07);
+	val |= (data->fan_div[1] & 0x07) << 3;
+	if (data->fan_div[2] == 3)
+		val |= 0x1 << 6;
+	it87_write_value(data, IT87_REG_FAN_DIV, val);
+
+	/* Restore fan min limit */
+	data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* Returns 0 if OK, -EINVAL otherwise */
+static int check_trip_points(struct device *dev, int nr)
+{
+	const struct it87_data *data = dev_get_drvdata(dev);
+	int i, err = 0;
+
+	if (has_old_autopwm(data)) {
+		for (i = 0; i < 3; i++) {
+			if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+				err = -EINVAL;
+		}
+		for (i = 0; i < 2; i++) {
+			if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
+				err = -EINVAL;
+		}
+	}
+
+	if (err) {
+		dev_err(dev,
+			"Inconsistent trip points, not switching to automatic mode\n");
+		dev_err(dev, "Adjust the trip points and try again\n");
+	}
+	return err;
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
+		return -EINVAL;
+
+	/* Check trip points before switching to automatic mode */
+	if (val == 2) {
+		if (check_trip_points(dev, nr) < 0)
+			return -EINVAL;
+	}
+
+	/* IT8603E does not have on/off mode */
+	if (val == 0 && data->type == it8603)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	if (val == 0) {
+		int tmp;
+		/* make sure the fan is on when in on/off mode */
+		tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+		it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
+		/* set on/off mode */
+		data->fan_main_ctrl &= ~(1 << nr);
+		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+				 data->fan_main_ctrl);
+	} else {
+		if (val == 1)				/* Manual mode */
+			data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
+					     data->pwm_temp_map[nr] :
+					     data->pwm_duty[nr];
+		else					/* Automatic mode */
+			data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
+		it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+
+		if (data->type != it8603) {
+			/* set SmartGuardian mode */
+			data->fan_main_ctrl |= (1 << nr);
+			it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+					 data->fan_main_ctrl);
+		}
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (has_newer_autopwm(data)) {
+		/*
+		 * If we are in automatic mode, the PWM duty cycle register
+		 * is read-only so we can't write the value.
+		 */
+		if (data->pwm_ctrl[nr] & 0x80) {
+			mutex_unlock(&data->update_lock);
+			return -EBUSY;
+		}
+		data->pwm_duty[nr] = pwm_to_reg(data, val);
+		it87_write_value(data, IT87_REG_PWM_DUTY(nr),
+				 data->pwm_duty[nr]);
+	} else {
+		data->pwm_duty[nr] = pwm_to_reg(data, val);
+		/*
+		 * If we are in manual mode, write the duty cycle immediately;
+		 * otherwise, just store it for later use.
+		 */
+		if (!(data->pwm_ctrl[nr] & 0x80)) {
+			data->pwm_ctrl[nr] = data->pwm_duty[nr];
+			it87_write_value(data, IT87_REG_PWM(nr),
+					 data->pwm_ctrl[nr]);
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_pwm_freq(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int i;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	val = clamp_val(val, 0, 1000000);
+	val *= has_newer_autopwm(data) ? 256 : 128;
+
+	/* Search for the nearest available frequency */
+	for (i = 0; i < 7; i++) {
+		if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
+			break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
+	data->fan_ctl |= i << 4;
+	it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+static ssize_t show_pwm_temp_map(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = it87_update_device(dev);
+	int map;
+
+	if (data->pwm_temp_map[nr] < 3)
+		map = 1 << data->pwm_temp_map[nr];
+	else
+		map = 0;			/* Should never happen */
+	return sprintf(buf, "%d\n", map);
+}
+static ssize_t set_pwm_temp_map(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+	u8 reg;
+
+	/*
+	 * This check can go away if we ever support automatic fan speed
+	 * control on newer chips.
+	 */
+	if (!has_old_autopwm(data)) {
+		dev_notice(dev, "Mapping change disabled for safety reasons\n");
+		return -EINVAL;
+	}
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	switch (val) {
+	case (1 << 0):
+		reg = 0x00;
+		break;
+	case (1 << 1):
+		reg = 0x01;
+		break;
+	case (1 << 2):
+		reg = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->pwm_temp_map[nr] = reg;
+	/*
+	 * If we are in automatic mode, write the temp mapping immediately;
+	 * otherwise, just store it for later use.
+	 */
+	if (data->pwm_ctrl[nr] & 0x80) {
+		data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
+		it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_auto_pwm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct it87_data *data = it87_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+			to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int point = sensor_attr->index;
+
+	return sprintf(buf, "%d\n",
+		       pwm_from_reg(data, data->auto_pwm[nr][point]));
+}
+
+static ssize_t set_auto_pwm(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+			to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int point = sensor_attr->index;
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
+	it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
+			 data->auto_pwm[nr][point]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_auto_temp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct it87_data *data = it87_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+			to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int point = sensor_attr->index;
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->auto_temp[nr][point]));
+}
+
+static ssize_t set_auto_temp(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+			to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int point = sensor_attr->index;
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->auto_temp[nr][point] = TEMP_TO_REG(val);
+	it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point),
+			 data->auto_temp[nr][point]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    0, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div,
+			  set_fan_div, 0);
+
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    1, 1);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div,
+			  set_fan_div, 1);
+
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    2, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div,
+			  set_fan_div, 2);
+
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    3, 1);
+
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    4, 1);
+
+static SENSOR_DEVICE_ATTR_2(fan6_input, S_IRUGO, show_fan, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+			    5, 1);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
+			  show_pwm_temp_map, set_pwm_temp_map, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO,
+			    show_auto_pwm, NULL, 0, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 0, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 0, 4);
+
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
+static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
+			  show_pwm_temp_map, set_pwm_temp_map, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO,
+			    show_auto_pwm, NULL, 1, 3);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 1, 3);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 1, 4);
+
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+			  show_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
+static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
+			  show_pwm_temp_map, set_pwm_temp_map, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			    show_auto_pwm, set_auto_pwm, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO,
+			    show_auto_pwm, NULL, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_auto_temp, set_auto_temp, 2, 4);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static ssize_t clear_intrusion(struct device *dev, struct device_attribute
+		*attr, const char *buf, size_t count)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+	int config;
+
+	if (kstrtol(buf, 10, &val) < 0 || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	config = it87_read_value(data, IT87_REG_CONFIG);
+	if (config < 0) {
+		count = config;
+	} else {
+		config |= 1 << 5;
+		it87_write_value(data, IT87_REG_CONFIG, config);
+		/* Invalidate cache to force re-read */
+		data->valid = 0;
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
+			  show_alarm, clear_intrusion, 4);
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
+}
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct it87_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0
+	 || (val != 0 && val != 1))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+	if (val)
+		data->beeps |= (1 << bitnr);
+	else
+		data->beeps &= ~(1 << bitnr);
+	it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+			  show_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO, show_beep, NULL, 1);
+/* fanX_beep writability is set later */
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan4_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan5_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan6_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+			  show_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);
+
+static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	data->vrm = val;
+
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct it87_data *data = it87_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_label(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	static const char * const labels[] = {
+		"+5V",
+		"5VSB",
+		"Vbat",
+	};
+	static const char * const labels_it8721[] = {
+		"+3.3V",
+		"3VSB",
+		"Vbat",
+	};
+	struct it87_data *data = dev_get_drvdata(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+	const char *label;
+
+	if (has_12mv_adc(data) || has_10_9mv_adc(data))
+		label = labels_it8721[nr];
+	else
+		label = labels[nr];
+
+	return sprintf(buf, "%s\n", label);
+}
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
+/* special AVCC3 IT8603E in9 */
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *it87_attributes_in[10][5] = {
+{
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	NULL
+} };
+
+static const struct attribute_group it87_group_in[10] = {
+	{ .attrs = it87_attributes_in[0] },
+	{ .attrs = it87_attributes_in[1] },
+	{ .attrs = it87_attributes_in[2] },
+	{ .attrs = it87_attributes_in[3] },
+	{ .attrs = it87_attributes_in[4] },
+	{ .attrs = it87_attributes_in[5] },
+	{ .attrs = it87_attributes_in[6] },
+	{ .attrs = it87_attributes_in[7] },
+	{ .attrs = it87_attributes_in[8] },
+	{ .attrs = it87_attributes_in[9] },
+};
+
+static struct attribute *it87_attributes_temp[3][6] = {
+{
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	NULL
+} , {
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	NULL
+} , {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	NULL
+} };
+
+static const struct attribute_group it87_group_temp[3] = {
+	{ .attrs = it87_attributes_temp[0] },
+	{ .attrs = it87_attributes_temp[1] },
+	{ .attrs = it87_attributes_temp[2] },
+};
+
+static struct attribute *it87_attributes_temp_offset[] = {
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+};
+
+static struct attribute *it87_attributes[] = {
+	&dev_attr_alarms.attr,
+	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group it87_group = {
+	.attrs = it87_attributes,
+};
+
+static struct attribute *it87_attributes_in_beep[] = {
+	&sensor_dev_attr_in0_beep.dev_attr.attr,
+	&sensor_dev_attr_in1_beep.dev_attr.attr,
+	&sensor_dev_attr_in2_beep.dev_attr.attr,
+	&sensor_dev_attr_in3_beep.dev_attr.attr,
+	&sensor_dev_attr_in4_beep.dev_attr.attr,
+	&sensor_dev_attr_in5_beep.dev_attr.attr,
+	&sensor_dev_attr_in6_beep.dev_attr.attr,
+	&sensor_dev_attr_in7_beep.dev_attr.attr,
+	NULL,
+	NULL,
+};
+
+static struct attribute *it87_attributes_temp_beep[] = {
+	&sensor_dev_attr_temp1_beep.dev_attr.attr,
+	&sensor_dev_attr_temp2_beep.dev_attr.attr,
+	&sensor_dev_attr_temp3_beep.dev_attr.attr,
+};
+
+static struct attribute *it87_attributes_fan[6][3+1] = { {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_min.dev_attr.attr,
+	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_min.dev_attr.attr,
+	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+	NULL
+} };
+
+static const struct attribute_group it87_group_fan[6] = {
+	{ .attrs = it87_attributes_fan[0] },
+	{ .attrs = it87_attributes_fan[1] },
+	{ .attrs = it87_attributes_fan[2] },
+	{ .attrs = it87_attributes_fan[3] },
+	{ .attrs = it87_attributes_fan[4] },
+	{ .attrs = it87_attributes_fan[5] },
+};
+
+static const struct attribute *it87_attributes_fan_div[] = {
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+};
+
+static struct attribute *it87_attributes_pwm[3][4+1] = { {
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&dev_attr_pwm1_freq.attr,
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&dev_attr_pwm2_freq.attr,
+	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&dev_attr_pwm3_freq.attr,
+	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+	NULL
+} };
+
+static const struct attribute_group it87_group_pwm[3] = {
+	{ .attrs = it87_attributes_pwm[0] },
+	{ .attrs = it87_attributes_pwm[1] },
+	{ .attrs = it87_attributes_pwm[2] },
+};
+
+static struct attribute *it87_attributes_autopwm[3][9+1] = { {
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
+	NULL
+}, {
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+	NULL
+} };
+
+static const struct attribute_group it87_group_autopwm[3] = {
+	{ .attrs = it87_attributes_autopwm[0] },
+	{ .attrs = it87_attributes_autopwm[1] },
+	{ .attrs = it87_attributes_autopwm[2] },
+};
+
+static struct attribute *it87_attributes_fan_beep[] = {
+	&sensor_dev_attr_fan1_beep.dev_attr.attr,
+	&sensor_dev_attr_fan2_beep.dev_attr.attr,
+	&sensor_dev_attr_fan3_beep.dev_attr.attr,
+	&sensor_dev_attr_fan4_beep.dev_attr.attr,
+	&sensor_dev_attr_fan5_beep.dev_attr.attr,
+	&sensor_dev_attr_fan6_beep.dev_attr.attr,
+};
+
+static struct attribute *it87_attributes_vid[] = {
+	&dev_attr_vrm.attr,
+	&dev_attr_cpu0_vid.attr,
+	NULL
+};
+
+static const struct attribute_group it87_group_vid = {
+	.attrs = it87_attributes_vid,
+};
+
+static struct attribute *it87_attributes_label[] = {
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	&sensor_dev_attr_in7_label.dev_attr.attr,
+	&sensor_dev_attr_in8_label.dev_attr.attr,
+	&sensor_dev_attr_in9_label.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group it87_group_label = {
+	.attrs = it87_attributes_label,
+};
+
+/* SuperIO detection - will change isa_address if a chip is found */
+static int __init it87_find(unsigned short *address,
+	struct it87_sio_data *sio_data)
+{
+	int err;
+	u16 chip_type;
+	const char *board_vendor, *board_name;
+	const struct it87_devices *config;
+
+	err = superio_enter();
+	if (err)
+		return err;
+
+	err = -ENODEV;
+	chip_type = force_id ? force_id : superio_inw(DEVID);
+
+	switch (chip_type) {
+	case IT8705F_DEVID:
+		sio_data->type = it87;
+		break;
+	case IT8712F_DEVID:
+		sio_data->type = it8712;
+		break;
+	case IT8716F_DEVID:
+	case IT8726F_DEVID:
+		sio_data->type = it8716;
+		break;
+	case IT8718F_DEVID:
+		sio_data->type = it8718;
+		break;
+	case IT8720F_DEVID:
+		sio_data->type = it8720;
+		break;
+	case IT8721F_DEVID:
+		sio_data->type = it8721;
+		break;
+	case IT8728F_DEVID:
+		sio_data->type = it8728;
+		break;
+	case IT8732F_DEVID:
+		sio_data->type = it8732;
+		break;
+	case IT8771E_DEVID:
+		sio_data->type = it8771;
+		break;
+	case IT8772E_DEVID:
+		sio_data->type = it8772;
+		break;
+	case IT8781F_DEVID:
+		sio_data->type = it8781;
+		break;
+	case IT8782F_DEVID:
+		sio_data->type = it8782;
+		break;
+	case IT8783E_DEVID:
+		sio_data->type = it8783;
+		break;
+	case IT8786E_DEVID:
+		sio_data->type = it8786;
+		break;
+	case IT8790E_DEVID:
+		sio_data->type = it8790;
+		break;
+	case IT8603E_DEVID:
+	case IT8623E_DEVID:
+		sio_data->type = it8603;
+		break;
+	case IT8620E_DEVID:
+		sio_data->type = it8620;
+		break;
+	case 0xffff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type);
+		goto exit;
+	}
+
+	superio_select(PME);
+	if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
+		pr_info("Device not activated, skipping\n");
+		goto exit;
+	}
+
+	*address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1);
+	if (*address == 0) {
+		pr_info("Base address not set, skipping\n");
+		goto exit;
+	}
+
+	err = 0;
+	sio_data->revision = superio_inb(DEVREV) & 0x0f;
+	pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
+		it87_devices[sio_data->type].suffix,
+		*address, sio_data->revision);
+
+	config = &it87_devices[sio_data->type];
+
+	/* in7 (VSB or VCCH5V) is always internal on some chips */
+	if (has_in7_internal(config))
+		sio_data->internal |= (1 << 1);
+
+	/* in8 (Vbat) is always internal */
+	sio_data->internal |= (1 << 2);
+
+	/* Only the IT8603E has in9 */
+	if (sio_data->type != it8603)
+		sio_data->skip_in |= (1 << 9);
+
+	if (!has_vid(config))
+		sio_data->skip_vid = 1;
+
+	/* Read GPIO config and VID value from LDN 7 (GPIO) */
+	if (sio_data->type == it87) {
+		/* The IT8705F has a different LD number for GPIO */
+		superio_select(5);
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	} else if (sio_data->type == it8783) {
+		int reg25, reg27, reg2a, reg2c, regef;
+
+		superio_select(GPIO);
+
+		reg25 = superio_inb(IT87_SIO_GPIO1_REG);
+		reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+		reg2a = superio_inb(IT87_SIO_PINX1_REG);
+		reg2c = superio_inb(IT87_SIO_PINX2_REG);
+		regef = superio_inb(IT87_SIO_SPI_REG);
+
+		/* Check if fan3 is there or not */
+		if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
+			sio_data->skip_fan |= (1 << 2);
+		if ((reg25 & (1 << 4))
+		    || (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
+			sio_data->skip_pwm |= (1 << 2);
+
+		/* Check if fan2 is there or not */
+		if (reg27 & (1 << 7))
+			sio_data->skip_fan |= (1 << 1);
+		if (reg27 & (1 << 3))
+			sio_data->skip_pwm |= (1 << 1);
+
+		/* VIN5 */
+		if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
+			sio_data->skip_in |= (1 << 5); /* No VIN5 */
+
+		/* VIN6 */
+		if (reg27 & (1 << 1))
+			sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+		/*
+		 * VIN7
+		 * Does not depend on bit 2 of Reg2C, contrary to datasheet.
+		 */
+		if (reg27 & (1 << 2)) {
+			/*
+			 * The data sheet is a bit unclear regarding the
+			 * internal voltage divider for VCCH5V. It says
+			 * "This bit enables and switches VIN7 (pin 91) to the
+			 * internal voltage divider for VCCH5V".
+			 * This is different to other chips, where the internal
+			 * voltage divider would connect VIN7 to an internal
+			 * voltage source. Maybe that is the case here as well.
+			 *
+			 * Since we don't know for sure, re-route it if that is
+			 * not the case, and ask the user to report if the
+			 * resulting voltage is sane.
+			 */
+			if (!(reg2c & (1 << 1))) {
+				reg2c |= (1 << 1);
+				superio_outb(IT87_SIO_PINX2_REG, reg2c);
+				pr_notice("Routing internal VCCH5V to in7.\n");
+			}
+			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
+			pr_notice("Please report if it displays a reasonable voltage.\n");
+		}
+
+		if (reg2c & (1 << 0))
+			sio_data->internal |= (1 << 0);
+		if (reg2c & (1 << 1))
+			sio_data->internal |= (1 << 1);
+
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	} else if (sio_data->type == it8603) {
+		int reg27, reg29;
+
+		superio_select(GPIO);
+
+		reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+
+		/* Check if fan3 is there or not */
+		if (reg27 & (1 << 6))
+			sio_data->skip_pwm |= (1 << 2);
+		if (reg27 & (1 << 7))
+			sio_data->skip_fan |= (1 << 2);
+
+		/* Check if fan2 is there or not */
+		reg29 = superio_inb(IT87_SIO_GPIO5_REG);
+		if (reg29 & (1 << 1))
+			sio_data->skip_pwm |= (1 << 1);
+		if (reg29 & (1 << 2))
+			sio_data->skip_fan |= (1 << 1);
+
+		sio_data->skip_in |= (1 << 5); /* No VIN5 */
+		sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+		sio_data->internal |= (1 << 3); /* in9 is AVCC */
+
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	} else if (sio_data->type == it8620) {
+		int reg;
+
+		superio_select(GPIO);
+
+		/* Check for fan4, fan5 */
+		reg = superio_inb(IT87_SIO_GPIO2_REG);
+		if (!(reg & (1 << 5)))
+			sio_data->skip_fan |= (1 << 3);
+		if (!(reg & (1 << 4)))
+			sio_data->skip_fan |= (1 << 4);
+
+		/* Check for pwm3, fan3 */
+		reg = superio_inb(IT87_SIO_GPIO3_REG);
+		if (reg & (1 << 6))
+			sio_data->skip_pwm |= (1 << 2);
+		if (reg & (1 << 7))
+			sio_data->skip_fan |= (1 << 2);
+
+		/* Check for pwm2, fan2 */
+		reg = superio_inb(IT87_SIO_GPIO5_REG);
+		if (reg & (1 << 1))
+			sio_data->skip_pwm |= (1 << 1);
+		if (reg & (1 << 2))
+			sio_data->skip_fan |= (1 << 1);
+
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	} else {
+		int reg;
+		bool uart6;
+
+		superio_select(GPIO);
+
+		reg = superio_inb(IT87_SIO_GPIO3_REG);
+		if (!sio_data->skip_vid) {
+			/* We need at least 4 VID pins */
+			if (reg & 0x0f) {
+				pr_info("VID is disabled (pins used for GPIO)\n");
+				sio_data->skip_vid = 1;
+			}
+		}
+
+		/* Check if fan3 is there or not */
+		if (reg & (1 << 6))
+			sio_data->skip_pwm |= (1 << 2);
+		if (reg & (1 << 7))
+			sio_data->skip_fan |= (1 << 2);
+
+		/* Check if fan2 is there or not */
+		reg = superio_inb(IT87_SIO_GPIO5_REG);
+		if (reg & (1 << 1))
+			sio_data->skip_pwm |= (1 << 1);
+		if (reg & (1 << 2))
+			sio_data->skip_fan |= (1 << 1);
+
+		if ((sio_data->type == it8718 || sio_data->type == it8720)
+		 && !(sio_data->skip_vid))
+			sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
+
+		reg = superio_inb(IT87_SIO_PINX2_REG);
+
+		uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+
+		/*
+		 * The IT8720F has no VIN7 pin, so VCCH should always be
+		 * routed internally to VIN7 with an internal divider.
+		 * Curiously, there still is a configuration bit to control
+		 * this, which means it can be set incorrectly. And even
+		 * more curiously, many boards out there are improperly
+		 * configured, even though the IT8720F datasheet claims
+		 * that the internal routing of VCCH to VIN7 is the default
+		 * setting. So we force the internal routing in this case.
+		 *
+		 * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
+		 * If UART6 is enabled, re-route VIN7 to the internal divider
+		 * if that is not already the case.
+		 */
+		if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
+			reg |= (1 << 1);
+			superio_outb(IT87_SIO_PINX2_REG, reg);
+			pr_notice("Routing internal VCCH to in7\n");
+		}
+		if (reg & (1 << 0))
+			sio_data->internal |= (1 << 0);
+		if (reg & (1 << 1))
+			sio_data->internal |= (1 << 1);
+
+		/*
+		 * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
+		 * While VIN7 can be routed to the internal voltage divider,
+		 * VIN5 and VIN6 are not available if UART6 is enabled.
+		 *
+		 * Also, temp3 is not available if UART6 is enabled and TEMPIN3
+		 * is the temperature source. Since we can not read the
+		 * temperature source here, skip_temp is preliminary.
+		 */
+		if (uart6) {
+			sio_data->skip_in |= (1 << 5) | (1 << 6);
+			sio_data->skip_temp |= (1 << 2);
+		}
+
+		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+	}
+	if (sio_data->beep_pin)
+		pr_info("Beeping is supported\n");
+
+	/* Disable specific features based on DMI strings */
+	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+	board_name = dmi_get_system_info(DMI_BOARD_NAME);
+	if (board_vendor && board_name) {
+		if (strcmp(board_vendor, "nVIDIA") == 0
+		 && strcmp(board_name, "FN68PT") == 0) {
+			/*
+			 * On the Shuttle SN68PT, FAN_CTL2 is apparently not
+			 * connected to a fan, but to something else. One user
+			 * has reported instant system power-off when changing
+			 * the PWM2 duty cycle, so we disable it.
+			 * I use the board name string as the trigger in case
+			 * the same board is ever used in other systems.
+			 */
+			pr_info("Disabling pwm2 due to hardware constraints\n");
+			sio_data->skip_pwm = (1 << 1);
+		}
+	}
+
+exit:
+	superio_exit();
+	return err;
+}
+
+static void it87_remove_files(struct device *dev)
+{
+	struct it87_data *data = platform_get_drvdata(pdev);
+	struct it87_sio_data *sio_data = dev_get_platdata(dev);
+	int i;
+
+	sysfs_remove_group(&dev->kobj, &it87_group);
+	for (i = 0; i < 10; i++) {
+		if (sio_data->skip_in & (1 << i))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
+		if (it87_attributes_in_beep[i])
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_in_beep[i]);
+	}
+	for (i = 0; i < 3; i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+		if (has_temp_offset(data))
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_temp_offset[i]);
+		if (sio_data->beep_pin)
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_temp_beep[i]);
+	}
+	for (i = 0; i < 6; i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_fan[i]);
+		if (sio_data->beep_pin)
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_fan_beep[i]);
+		if (i < 3 && !has_16bit_fans(data))
+			sysfs_remove_file(&dev->kobj,
+					  it87_attributes_fan_div[i]);
+	}
+	for (i = 0; i < 3; i++) {
+		if (sio_data->skip_pwm & (1 << i))
+			continue;
+		sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
+		if (has_old_autopwm(data))
+			sysfs_remove_group(&dev->kobj,
+					   &it87_group_autopwm[i]);
+	}
+	if (!sio_data->skip_vid)
+		sysfs_remove_group(&dev->kobj, &it87_group_vid);
+	sysfs_remove_group(&dev->kobj, &it87_group_label);
+}
+
+static int it87_probe(struct platform_device *pdev)
+{
+	struct it87_data *data;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct it87_sio_data *sio_data = dev_get_platdata(dev);
+	int err = 0, i;
+	int enable_pwm_interface;
+	int fan_beep_need_rw;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+				 DRVNAME)) {
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)(res->start + IT87_EC_EXTENT - 1));
+		return -EBUSY;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->features = it87_devices[sio_data->type].features;
+	data->peci_mask = it87_devices[sio_data->type].peci_mask;
+	data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
+	data->name = it87_devices[sio_data->type].name;
+	/*
+	 * IT8705F Datasheet 0.4.1, 3h == Version G.
+	 * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
+	 * These are the first revisions with 16-bit tachometer support.
+	 */
+	switch (data->type) {
+	case it87:
+		if (sio_data->revision >= 0x03) {
+			data->features &= ~FEAT_OLD_AUTOPWM;
+			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
+		}
+		break;
+	case it8712:
+		if (sio_data->revision >= 0x08) {
+			data->features &= ~FEAT_OLD_AUTOPWM;
+			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
+					  FEAT_FIVE_FANS;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* Now, we do the remaining detection. */
+	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+	 || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, data);
+
+	mutex_init(&data->update_lock);
+
+	/* Check PWM configuration */
+	enable_pwm_interface = it87_check_pwm(dev);
+
+	/* Starting with IT8721F, we handle scaling of internal voltages */
+	if (has_12mv_adc(data)) {
+		if (sio_data->internal & (1 << 0))
+			data->in_scaled |= (1 << 3);	/* in3 is AVCC */
+		if (sio_data->internal & (1 << 1))
+			data->in_scaled |= (1 << 7);	/* in7 is VSB */
+		if (sio_data->internal & (1 << 2))
+			data->in_scaled |= (1 << 8);	/* in8 is Vbat */
+		if (sio_data->internal & (1 << 3))
+			data->in_scaled |= (1 << 9);	/* in9 is AVCC */
+	} else if (sio_data->type == it8781 || sio_data->type == it8782 ||
+		   sio_data->type == it8783) {
+		if (sio_data->internal & (1 << 0))
+			data->in_scaled |= (1 << 3);	/* in3 is VCC5V */
+		if (sio_data->internal & (1 << 1))
+			data->in_scaled |= (1 << 7);	/* in7 is VCCH5V */
+	}
+
+	data->has_temp = 0x07;
+	if (sio_data->skip_temp & (1 << 2)) {
+		if (sio_data->type == it8782
+		    && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+			data->has_temp &= ~(1 << 2);
+	}
+
+	/* Initialize the IT87 chip */
+	it87_init_device(pdev);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&dev->kobj, &it87_group);
+	if (err)
+		return err;
+
+	for (i = 0; i < 10; i++) {
+		if (sio_data->skip_in & (1 << i))
+			continue;
+		err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
+		if (err)
+			goto error;
+		if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_in_beep[i]);
+			if (err)
+				goto error;
+		}
+	}
+
+	for (i = 0; i < 3; i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
+		if (err)
+			goto error;
+		if (has_temp_offset(data)) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_temp_offset[i]);
+			if (err)
+				goto error;
+		}
+		if (sio_data->beep_pin) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_temp_beep[i]);
+			if (err)
+				goto error;
+		}
+	}
+
+	/* Do not create fan files for disabled fans */
+	fan_beep_need_rw = 1;
+	for (i = 0; i < 6; i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]);
+		if (err)
+			goto error;
+
+		if (i < 3 && !has_16bit_fans(data)) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_fan_div[i]);
+			if (err)
+				goto error;
+		}
+
+		if (sio_data->beep_pin) {
+			err = sysfs_create_file(&dev->kobj,
+						it87_attributes_fan_beep[i]);
+			if (err)
+				goto error;
+			if (!fan_beep_need_rw)
+				continue;
+
+			/*
+			 * As we have a single beep enable bit for all fans,
+			 * only the first enabled fan has a writable attribute
+			 * for it.
+			 */
+			if (sysfs_chmod_file(&dev->kobj,
+					     it87_attributes_fan_beep[i],
+					     S_IRUGO | S_IWUSR))
+				dev_dbg(dev, "chmod +w fan%d_beep failed\n",
+					i + 1);
+			fan_beep_need_rw = 0;
+		}
+	}
+
+	if (enable_pwm_interface) {
+		for (i = 0; i < 3; i++) {
+			if (sio_data->skip_pwm & (1 << i))
+				continue;
+			err = sysfs_create_group(&dev->kobj,
+						 &it87_group_pwm[i]);
+			if (err)
+				goto error;
+
+			if (!has_old_autopwm(data))
+				continue;
+			err = sysfs_create_group(&dev->kobj,
+						 &it87_group_autopwm[i]);
+			if (err)
+				goto error;
+		}
+	}
+
+	if (!sio_data->skip_vid) {
+		data->vrm = vid_which_vrm();
+		/* VID reading from Super-I/O config space if available */
+		data->vid = sio_data->vid_value;
+		err = sysfs_create_group(&dev->kobj, &it87_group_vid);
+		if (err)
+			goto error;
+	}
+
+	/* Export labels for internal sensors */
+	for (i = 0; i < 4; i++) {
+		if (!(sio_data->internal & (1 << i)))
+			continue;
+		err = sysfs_create_file(&dev->kobj,
+					it87_attributes_label[i]);
+		if (err)
+			goto error;
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	it87_remove_files(dev);
+	return err;
+}
+
+static int it87_remove(struct platform_device *pdev)
+{
+	struct it87_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	it87_remove_files(&pdev->dev);
+
+	return 0;
+}
+
+/*
+ * Must be called with data->update_lock held, except during initialization.
+ * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the IT87 access and should not be necessary.
+ */
+static int it87_read_value(struct it87_data *data, u8 reg)
+{
+	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+	return inb_p(data->addr + IT87_DATA_REG_OFFSET);
+}
+
+/*
+ * Must be called with data->update_lock held, except during initialization.
+ * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the IT87 access and should not be necessary.
+ */
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
+{
+	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+	outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
+}
+
+/* Return 1 if and only if the PWM interface is safe to use */
+static int it87_check_pwm(struct device *dev)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	/*
+	 * Some BIOSes fail to correctly configure the IT87 fans. All fans off
+	 * and polarity set to active low is sign that this is the case so we
+	 * disable pwm control to protect the user.
+	 */
+	int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+	if ((tmp & 0x87) == 0) {
+		if (fix_pwm_polarity) {
+			/*
+			 * The user asks us to attempt a chip reconfiguration.
+			 * This means switching to active high polarity and
+			 * inverting all fan speed values.
+			 */
+			int i;
+			u8 pwm[3];
+
+			for (i = 0; i < 3; i++)
+				pwm[i] = it87_read_value(data,
+							 IT87_REG_PWM(i));
+
+			/*
+			 * If any fan is in automatic pwm mode, the polarity
+			 * might be correct, as suspicious as it seems, so we
+			 * better don't change anything (but still disable the
+			 * PWM interface).
+			 */
+			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
+				dev_info(dev,
+					 "Reconfiguring PWM to active high polarity\n");
+				it87_write_value(data, IT87_REG_FAN_CTL,
+						 tmp | 0x87);
+				for (i = 0; i < 3; i++)
+					it87_write_value(data,
+							 IT87_REG_PWM(i),
+							 0x7f & ~pwm[i]);
+				return 1;
+			}
+
+			dev_info(dev,
+				 "PWM configuration is too broken to be fixed\n");
+		}
+
+		dev_info(dev,
+			 "Detected broken BIOS defaults, disabling PWM interface\n");
+		return 0;
+	} else if (fix_pwm_polarity) {
+		dev_info(dev,
+			 "PWM configuration looks sane, won't touch\n");
+	}
+
+	return 1;
+}
+
+/* Called when we have found a new IT87. */
+static void it87_init_device(struct platform_device *pdev)
+{
+	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	struct it87_data *data = platform_get_drvdata(pdev);
+	int tmp, i;
+	u8 mask;
+
+	/*
+	 * For each PWM channel:
+	 * - If it is in automatic mode, setting to manual mode should set
+	 *   the fan to full speed by default.
+	 * - If it is in manual mode, we need a mapping to temperature
+	 *   channels to use when later setting to automatic mode later.
+	 *   Use a 1:1 mapping by default (we are clueless.)
+	 * In both cases, the value can (and should) be changed by the user
+	 * prior to switching to a different mode.
+	 * Note that this is no longer needed for the IT8721F and later, as
+	 * these have separate registers for the temperature mapping and the
+	 * manual duty cycle.
+	 */
+	for (i = 0; i < 3; i++) {
+		data->pwm_temp_map[i] = i;
+		data->pwm_duty[i] = 0x7f;	/* Full speed */
+		data->auto_pwm[i][3] = 0x7f;	/* Full speed, hard-coded */
+	}
+
+	/*
+	 * Some chips seem to have default value 0xff for all limit
+	 * registers. For low voltage limits it makes no sense and triggers
+	 * alarms, so change to 0 instead. For high temperature limits, it
+	 * means -1 degree C, which surprisingly doesn't trigger an alarm,
+	 * but is still confusing, so change to 127 degrees C.
+	 */
+	for (i = 0; i < 8; i++) {
+		tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
+		if (tmp == 0xff)
+			it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
+	}
+	for (i = 0; i < 3; i++) {
+		tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+		if (tmp == 0xff)
+			it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
+	}
+
+	/*
+	 * Temperature channels are not forcibly enabled, as they can be
+	 * set to two different sensor types and we can't guess which one
+	 * is correct for a given system. These channels can be enabled at
+	 * run-time through the temp{1-3}_type sysfs accessors if needed.
+	 */
+
+	/* Check if voltage monitors are reset manually or by some reason */
+	tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
+	if ((tmp & 0xff) == 0) {
+		/* Enable all voltage monitors */
+		it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
+	}
+
+	/* Check if tachometers are reset manually or by some reason */
+	mask = 0x70 & ~(sio_data->skip_fan << 4);
+	data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
+	if ((data->fan_main_ctrl & mask) == 0) {
+		/* Enable all fan tachometers */
+		data->fan_main_ctrl |= mask;
+		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+				 data->fan_main_ctrl);
+	}
+	data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
+
+	tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
+
+	/* Set tachometers to 16-bit mode if needed */
+	if (has_fan16_config(data)) {
+		if (~tmp & 0x07 & data->has_fan) {
+			dev_dbg(&pdev->dev,
+				"Setting fan1-3 to 16-bit mode\n");
+			it87_write_value(data, IT87_REG_FAN_16BIT,
+					 tmp | 0x07);
+		}
+	}
+
+	/* Check for additional fans */
+	if (has_five_fans(data)) {
+		if (tmp & (1 << 4))
+			data->has_fan |= (1 << 3); /* fan4 enabled */
+		if (tmp & (1 << 5))
+			data->has_fan |= (1 << 4); /* fan5 enabled */
+		if (has_six_fans(data) && (tmp & (1 << 2)))
+			data->has_fan |= (1 << 5); /* fan6 enabled */
+	}
+
+	/* Fan input pins may be used for alternative functions */
+	data->has_fan &= ~sio_data->skip_fan;
+
+	/* Start monitoring */
+	it87_write_value(data, IT87_REG_CONFIG,
+			 (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
+			 | (update_vbat ? 0x41 : 0x01));
+}
+
+static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
+{
+	data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
+	if (has_newer_autopwm(data)) {
+		data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+		data->pwm_duty[nr] = it87_read_value(data,
+						     IT87_REG_PWM_DUTY(nr));
+	} else {
+		if (data->pwm_ctrl[nr] & 0x80)	/* Automatic mode */
+			data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+		else				/* Manual mode */
+			data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+	}
+
+	if (has_old_autopwm(data)) {
+		int i;
+
+		for (i = 0; i < 5 ; i++)
+			data->auto_temp[nr][i] = it87_read_value(data,
+						IT87_REG_AUTO_TEMP(nr, i));
+		for (i = 0; i < 3 ; i++)
+			data->auto_pwm[nr][i] = it87_read_value(data,
+						IT87_REG_AUTO_PWM(nr, i));
+	}
+}
+
+static struct it87_data *it87_update_device(struct device *dev)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		if (update_vbat) {
+			/*
+			 * Cleared after each update, so reenable.  Value
+			 * returned by this read will be previous value
+			 */
+			it87_write_value(data, IT87_REG_CONFIG,
+				it87_read_value(data, IT87_REG_CONFIG) | 0x40);
+		}
+		for (i = 0; i <= 7; i++) {
+			data->in[i][0] =
+				it87_read_value(data, IT87_REG_VIN(i));
+			data->in[i][1] =
+				it87_read_value(data, IT87_REG_VIN_MIN(i));
+			data->in[i][2] =
+				it87_read_value(data, IT87_REG_VIN_MAX(i));
+		}
+		/* in8 (battery) has no limit registers */
+		data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
+		if (data->type == it8603)
+			data->in[9][0] = it87_read_value(data, 0x2f);
+
+		for (i = 0; i < 6; i++) {
+			/* Skip disabled fans */
+			if (!(data->has_fan & (1 << i)))
+				continue;
+
+			data->fan[i][1] =
+				it87_read_value(data, IT87_REG_FAN_MIN[i]);
+			data->fan[i][0] = it87_read_value(data,
+				       IT87_REG_FAN[i]);
+			/* Add high byte if in 16-bit mode */
+			if (has_16bit_fans(data)) {
+				data->fan[i][0] |= it87_read_value(data,
+						IT87_REG_FANX[i]) << 8;
+				data->fan[i][1] |= it87_read_value(data,
+						IT87_REG_FANX_MIN[i]) << 8;
+			}
+		}
+		for (i = 0; i < 3; i++) {
+			if (!(data->has_temp & (1 << i)))
+				continue;
+			data->temp[i][0] =
+				it87_read_value(data, IT87_REG_TEMP(i));
+			data->temp[i][1] =
+				it87_read_value(data, IT87_REG_TEMP_LOW(i));
+			data->temp[i][2] =
+				it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+			if (has_temp_offset(data))
+				data->temp[i][3] =
+				  it87_read_value(data,
+						  IT87_REG_TEMP_OFFSET[i]);
+		}
+
+		/* Newer chips don't have clock dividers */
+		if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
+			i = it87_read_value(data, IT87_REG_FAN_DIV);
+			data->fan_div[0] = i & 0x07;
+			data->fan_div[1] = (i >> 3) & 0x07;
+			data->fan_div[2] = (i & 0x40) ? 3 : 1;
+		}
+
+		data->alarms =
+			it87_read_value(data, IT87_REG_ALARM1) |
+			(it87_read_value(data, IT87_REG_ALARM2) << 8) |
+			(it87_read_value(data, IT87_REG_ALARM3) << 16);
+		data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+
+		data->fan_main_ctrl = it87_read_value(data,
+				IT87_REG_FAN_MAIN_CTRL);
+		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+		for (i = 0; i < 3; i++)
+			it87_update_pwm_ctrl(data, i);
+
+		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+		data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+		/*
+		 * The IT8705F does not have VID capability.
+		 * The IT8718F and later don't use IT87_REG_VID for the
+		 * same purpose.
+		 */
+		if (data->type == it8712 || data->type == it8716) {
+			data->vid = it87_read_value(data, IT87_REG_VID);
+			/*
+			 * The older IT8712F revisions had only 5 VID pins,
+			 * but we assume it is always safe to read 6 bits.
+			 */
+			data->vid &= 0x3f;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int __init it87_device_add(unsigned short address,
+				  const struct it87_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address + IT87_EC_OFFSET,
+		.end	= address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct it87_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init sm_it87_init(void)
+{
+	int err;
+	unsigned short isa_address = 0;
+	struct it87_sio_data sio_data;
+
+	memset(&sio_data, 0, sizeof(struct it87_sio_data));
+	err = it87_find(&isa_address, &sio_data);
+	if (err)
+		return err;
+	err = platform_driver_register(&it87_driver);
+	if (err)
+		return err;
+
+	err = it87_device_add(isa_address, &sio_data);
+	if (err) {
+		platform_driver_unregister(&it87_driver);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit sm_it87_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&it87_driver);
+}
+
+
+MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
+module_param(update_vbat, bool, 0);
+MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
+module_param(fix_pwm_polarity, bool, 0);
+MODULE_PARM_DESC(fix_pwm_polarity,
+		 "Force PWM polarity to active high (DANGEROUS)");
+MODULE_LICENSE("GPL");
+
+module_init(sm_it87_init);
+module_exit(sm_it87_exit);
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
new file mode 100644
index 0000000..9887d32
--- /dev/null
+++ b/drivers/hwmon/jc42.c
@@ -0,0 +1,557 @@
+/*
+ * jc42.c - driver for Jedec JC42.4 compliant temperature sensors
+ *
+ * Copyright (c) 2010  Ericsson AB.
+ *
+ * Derived from lm77.c by Andras BALI <drewie@freemail.hu>.
+ *
+ * JC42.4 compliant temperature sensors are typically used on memory modules.
+ *
+ * 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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, I2C_CLIENT_END };
+
+/* JC42 registers. All registers are 16 bit. */
+#define JC42_REG_CAP		0x00
+#define JC42_REG_CONFIG		0x01
+#define JC42_REG_TEMP_UPPER	0x02
+#define JC42_REG_TEMP_LOWER	0x03
+#define JC42_REG_TEMP_CRITICAL	0x04
+#define JC42_REG_TEMP		0x05
+#define JC42_REG_MANID		0x06
+#define JC42_REG_DEVICEID	0x07
+
+/* Status bits in temperature register */
+#define JC42_ALARM_CRIT_BIT	15
+#define JC42_ALARM_MAX_BIT	14
+#define JC42_ALARM_MIN_BIT	13
+
+/* Configuration register defines */
+#define JC42_CFG_CRIT_ONLY	(1 << 2)
+#define JC42_CFG_TCRIT_LOCK	(1 << 6)
+#define JC42_CFG_EVENT_LOCK	(1 << 7)
+#define JC42_CFG_SHUTDOWN	(1 << 8)
+#define JC42_CFG_HYST_SHIFT	9
+#define JC42_CFG_HYST_MASK	(0x03 << 9)
+
+/* Capabilities */
+#define JC42_CAP_RANGE		(1 << 2)
+
+/* Manufacturer IDs */
+#define ADT_MANID		0x11d4  /* Analog Devices */
+#define ATMEL_MANID		0x001f  /* Atmel */
+#define ATMEL_MANID2		0x1114	/* Atmel */
+#define MAX_MANID		0x004d  /* Maxim */
+#define IDT_MANID		0x00b3  /* IDT */
+#define MCP_MANID		0x0054  /* Microchip */
+#define NXP_MANID		0x1131  /* NXP Semiconductors */
+#define ONS_MANID		0x1b09  /* ON Semiconductor */
+#define STM_MANID		0x104a  /* ST Microelectronics */
+
+/* Supported chips */
+
+/* Analog Devices */
+#define ADT7408_DEVID		0x0801
+#define ADT7408_DEVID_MASK	0xffff
+
+/* Atmel */
+#define AT30TS00_DEVID		0x8201
+#define AT30TS00_DEVID_MASK	0xffff
+
+#define AT30TSE004_DEVID	0x2200
+#define AT30TSE004_DEVID_MASK	0xffff
+
+/* IDT */
+#define TSE2004_DEVID		0x2200
+#define TSE2004_DEVID_MASK	0xff00
+
+#define TS3000_DEVID		0x2900  /* Also matches TSE2002 */
+#define TS3000_DEVID_MASK	0xff00
+
+#define TS3001_DEVID		0x3000
+#define TS3001_DEVID_MASK	0xff00
+
+/* Maxim */
+#define MAX6604_DEVID		0x3e00
+#define MAX6604_DEVID_MASK	0xffff
+
+/* Microchip */
+#define MCP9804_DEVID		0x0200
+#define MCP9804_DEVID_MASK	0xfffc
+
+#define MCP98242_DEVID		0x2000
+#define MCP98242_DEVID_MASK	0xfffc
+
+#define MCP98243_DEVID		0x2100
+#define MCP98243_DEVID_MASK	0xfffc
+
+#define MCP98244_DEVID		0x2200
+#define MCP98244_DEVID_MASK	0xfffc
+
+#define MCP9843_DEVID		0x0000	/* Also matches mcp9805 */
+#define MCP9843_DEVID_MASK	0xfffe
+
+/* NXP */
+#define SE97_DEVID		0xa200
+#define SE97_DEVID_MASK		0xfffc
+
+#define SE98_DEVID		0xa100
+#define SE98_DEVID_MASK		0xfffc
+
+/* ON Semiconductor */
+#define CAT6095_DEVID		0x0800	/* Also matches CAT34TS02 */
+#define CAT6095_DEVID_MASK	0xffe0
+
+/* ST Microelectronics */
+#define STTS424_DEVID		0x0101
+#define STTS424_DEVID_MASK	0xffff
+
+#define STTS424E_DEVID		0x0000
+#define STTS424E_DEVID_MASK	0xfffe
+
+#define STTS2002_DEVID		0x0300
+#define STTS2002_DEVID_MASK	0xffff
+
+#define STTS2004_DEVID		0x2201
+#define STTS2004_DEVID_MASK	0xffff
+
+#define STTS3000_DEVID		0x0200
+#define STTS3000_DEVID_MASK	0xffff
+
+static u16 jc42_hysteresis[] = { 0, 1500, 3000, 6000 };
+
+struct jc42_chips {
+	u16 manid;
+	u16 devid;
+	u16 devid_mask;
+};
+
+static struct jc42_chips jc42_chips[] = {
+	{ ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
+	{ ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
+	{ ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK },
+	{ IDT_MANID, TSE2004_DEVID, TSE2004_DEVID_MASK },
+	{ IDT_MANID, TS3000_DEVID, TS3000_DEVID_MASK },
+	{ IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK },
+	{ MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
+	{ MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
+	{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
+	{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
+	{ MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
+	{ MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
+	{ NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
+	{ ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
+	{ NXP_MANID, SE98_DEVID, SE98_DEVID_MASK },
+	{ STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
+	{ STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
+	{ STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
+	{ STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK },
+	{ STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
+};
+
+enum temp_index {
+	t_input = 0,
+	t_crit,
+	t_min,
+	t_max,
+	t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+	[t_input] = JC42_REG_TEMP,
+	[t_crit] = JC42_REG_TEMP_CRITICAL,
+	[t_min] = JC42_REG_TEMP_LOWER,
+	[t_max] = JC42_REG_TEMP_UPPER,
+};
+
+/* Each client has this additional data */
+struct jc42_data {
+	struct i2c_client *client;
+	struct mutex	update_lock;	/* protect register access */
+	bool		extended;	/* true if extended range supported */
+	bool		valid;
+	unsigned long	last_updated;	/* In jiffies */
+	u16		orig_config;	/* original configuration */
+	u16		config;		/* current configuration */
+	u16		temp[t_num_temp];/* Temperatures */
+};
+
+#define JC42_TEMP_MIN_EXTENDED	(-40000)
+#define JC42_TEMP_MIN		0
+#define JC42_TEMP_MAX		125000
+
+static u16 jc42_temp_to_reg(long temp, bool extended)
+{
+	int ntemp = clamp_val(temp,
+			      extended ? JC42_TEMP_MIN_EXTENDED :
+			      JC42_TEMP_MIN, JC42_TEMP_MAX);
+
+	/* convert from 0.001 to 0.0625 resolution */
+	return (ntemp * 2 / 125) & 0x1fff;
+}
+
+static int jc42_temp_from_reg(s16 reg)
+{
+	reg = sign_extend32(reg, 12);
+
+	/* convert from 0.0625 to 0.001 resolution */
+	return reg * 125 / 2;
+}
+
+static struct jc42_data *jc42_update_device(struct device *dev)
+{
+	struct jc42_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct jc42_data *ret = data;
+	int i, val;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		for (i = 0; i < t_num_temp; i++) {
+			val = i2c_smbus_read_word_swapped(client, temp_regs[i]);
+			if (val < 0) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* sysfs functions */
+
+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 jc42_data *data = jc42_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%d\n",
+		       jc42_temp_from_reg(data->temp[attr->index]));
+}
+
+static ssize_t show_temp_hyst(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct jc42_data *data = jc42_update_device(dev);
+	int temp, hyst;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = jc42_temp_from_reg(data->temp[attr->index]);
+	hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
+			       >> JC42_CFG_HYST_SHIFT];
+	return sprintf(buf, "%d\n", temp - hyst);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct jc42_data *data = dev_get_drvdata(dev);
+	int err, ret = count;
+	int nr = attr->index;
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = jc42_temp_to_reg(val, data->extended);
+	err = i2c_smbus_write_word_swapped(data->client, temp_regs[nr],
+					   data->temp[nr]);
+	if (err < 0)
+		ret = err;
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/*
+ * JC42.4 compliant chips only support four hysteresis values.
+ * Pick best choice and go from there.
+ */
+static ssize_t set_temp_crit_hyst(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct jc42_data *data = dev_get_drvdata(dev);
+	long val;
+	int diff, hyst;
+	int err;
+	int ret = count;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED :
+			      JC42_TEMP_MIN) - 6000, JC42_TEMP_MAX);
+	diff = jc42_temp_from_reg(data->temp[t_crit]) - val;
+
+	hyst = 0;
+	if (diff > 0) {
+		if (diff < 2250)
+			hyst = 1;	/* 1.5 degrees C */
+		else if (diff < 4500)
+			hyst = 2;	/* 3.0 degrees C */
+		else
+			hyst = 3;	/* 6.0 degrees C */
+	}
+
+	mutex_lock(&data->update_lock);
+	data->config = (data->config & ~JC42_CFG_HYST_MASK)
+	  | (hyst << JC42_CFG_HYST_SHIFT);
+	err = i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
+					   data->config);
+	if (err < 0)
+		ret = err;
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	u16 bit = to_sensor_dev_attr(attr)->index;
+	struct jc42_data *data = jc42_update_device(dev);
+	u16 val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = data->temp[t_input];
+	if (bit != JC42_ALARM_CRIT_BIT && (data->config & JC42_CFG_CRIT_ONLY))
+		val = 0;
+	return sprintf(buf, "%u\n", (val >> bit) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, set_temp, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, set_temp, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, set_temp, t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_hyst,
+			  set_temp_crit_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+			  JC42_ALARM_CRIT_BIT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+			  JC42_ALARM_MIN_BIT);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+			  JC42_ALARM_MAX_BIT);
+
+static struct attribute *jc42_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+
+static umode_t jc42_attribute_mode(struct kobject *kobj,
+				  struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct jc42_data *data = dev_get_drvdata(dev);
+	unsigned int config = data->config;
+	bool readonly;
+
+	if (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr)
+		readonly = config & JC42_CFG_TCRIT_LOCK;
+	else if (attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
+		 attr == &sensor_dev_attr_temp1_max.dev_attr.attr)
+		readonly = config & JC42_CFG_EVENT_LOCK;
+	else if (attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)
+		readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
+	else
+		readonly = true;
+
+	return S_IRUGO | (readonly ? 0 : S_IWUSR);
+}
+
+static const struct attribute_group jc42_group = {
+	.attrs = jc42_attributes,
+	.is_visible = jc42_attribute_mode,
+};
+__ATTRIBUTE_GROUPS(jc42);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int i, config, cap, manid, devid;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
+	config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
+	manid = i2c_smbus_read_word_swapped(client, JC42_REG_MANID);
+	devid = i2c_smbus_read_word_swapped(client, JC42_REG_DEVICEID);
+
+	if (cap < 0 || config < 0 || manid < 0 || devid < 0)
+		return -ENODEV;
+
+	if ((cap & 0xff00) || (config & 0xf800))
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(jc42_chips); i++) {
+		struct jc42_chips *chip = &jc42_chips[i];
+		if (manid == chip->manid &&
+		    (devid & chip->devid_mask) == chip->devid) {
+			strlcpy(info->type, "jc42", I2C_NAME_SIZE);
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct jc42_data *data;
+	int config, cap;
+
+	data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
+	if (cap < 0)
+		return cap;
+
+	data->extended = !!(cap & JC42_CAP_RANGE);
+
+	config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
+	if (config < 0)
+		return config;
+
+	data->orig_config = config;
+	if (config & JC42_CFG_SHUTDOWN) {
+		config &= ~JC42_CFG_SHUTDOWN;
+		i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
+	}
+	data->config = config;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   jc42_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static int jc42_remove(struct i2c_client *client)
+{
+	struct jc42_data *data = i2c_get_clientdata(client);
+
+	/* Restore original configuration except hysteresis */
+	if ((data->config & ~JC42_CFG_HYST_MASK) !=
+	    (data->orig_config & ~JC42_CFG_HYST_MASK)) {
+		int config;
+
+		config = (data->orig_config & ~JC42_CFG_HYST_MASK)
+		  | (data->config & JC42_CFG_HYST_MASK);
+		i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int jc42_suspend(struct device *dev)
+{
+	struct jc42_data *data = dev_get_drvdata(dev);
+
+	data->config |= JC42_CFG_SHUTDOWN;
+	i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
+				     data->config);
+	return 0;
+}
+
+static int jc42_resume(struct device *dev)
+{
+	struct jc42_data *data = dev_get_drvdata(dev);
+
+	data->config &= ~JC42_CFG_SHUTDOWN;
+	i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
+				     data->config);
+	return 0;
+}
+
+static const struct dev_pm_ops jc42_dev_pm_ops = {
+	.suspend = jc42_suspend,
+	.resume = jc42_resume,
+};
+
+#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
+#else
+#define JC42_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id jc42_id[] = {
+	{ "jc42", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, jc42_id);
+
+static struct i2c_driver jc42_driver = {
+	.class		= I2C_CLASS_SPD,
+	.driver = {
+		.name	= "jc42",
+		.pm = JC42_DEV_PM_OPS,
+	},
+	.probe		= jc42_probe,
+	.remove		= jc42_remove,
+	.id_table	= jc42_id,
+	.detect		= jc42_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(jc42_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("JC42 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
new file mode 100644
index 0000000..df9b344
--- /dev/null
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC HWMON driver
+ *
+ * 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.
+ *
+ * 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/completion.h>
+#include <linux/mfd/core.h>
+
+#include <linux/hwmon.h>
+
+struct jz4740_hwmon {
+	void __iomem *base;
+
+	int irq;
+
+	const struct mfd_cell *cell;
+	struct device *hwmon;
+
+	struct completion read_completion;
+
+	struct mutex lock;
+};
+
+static ssize_t jz4740_hwmon_show_name(struct device *dev,
+	struct device_attribute *dev_attr, char *buf)
+{
+	return sprintf(buf, "jz4740\n");
+}
+
+static irqreturn_t jz4740_hwmon_irq(int irq, void *data)
+{
+	struct jz4740_hwmon *hwmon = data;
+
+	complete(&hwmon->read_completion);
+	return IRQ_HANDLED;
+}
+
+static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
+	struct device_attribute *dev_attr, char *buf)
+{
+	struct jz4740_hwmon *hwmon = dev_get_drvdata(dev);
+	struct completion *completion = &hwmon->read_completion;
+	long t;
+	unsigned long val;
+	int ret;
+
+	mutex_lock(&hwmon->lock);
+
+	reinit_completion(completion);
+
+	enable_irq(hwmon->irq);
+	hwmon->cell->enable(to_platform_device(dev));
+
+	t = wait_for_completion_interruptible_timeout(completion, HZ);
+
+	if (t > 0) {
+		val = readw(hwmon->base) & 0xfff;
+		val = (val * 3300) >> 12;
+		ret = sprintf(buf, "%lu\n", val);
+	} else {
+		ret = t ? t : -ETIMEDOUT;
+	}
+
+	hwmon->cell->disable(to_platform_device(dev));
+	disable_irq(hwmon->irq);
+
+	mutex_unlock(&hwmon->lock);
+
+	return ret;
+}
+
+static DEVICE_ATTR(name, S_IRUGO, jz4740_hwmon_show_name, NULL);
+static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL);
+
+static struct attribute *jz4740_hwmon_attributes[] = {
+	&dev_attr_name.attr,
+	&dev_attr_in0_input.attr,
+	NULL
+};
+
+static const struct attribute_group jz4740_hwmon_attr_group = {
+	.attrs = jz4740_hwmon_attributes,
+};
+
+static int jz4740_hwmon_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct jz4740_hwmon *hwmon;
+	struct resource *mem;
+
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	hwmon->cell = mfd_get_cell(pdev);
+
+	hwmon->irq = platform_get_irq(pdev, 0);
+	if (hwmon->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+			hwmon->irq);
+		return hwmon->irq;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hwmon->base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(hwmon->base))
+		return PTR_ERR(hwmon->base);
+
+	init_completion(&hwmon->read_completion);
+	mutex_init(&hwmon->lock);
+
+	platform_set_drvdata(pdev, hwmon);
+
+	ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
+			       pdev->name, hwmon);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
+		return ret;
+	}
+	disable_irq(hwmon->irq);
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
+		return ret;
+	}
+
+	hwmon->hwmon = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(hwmon->hwmon)) {
+		ret = PTR_ERR(hwmon->hwmon);
+		goto err_remove_file;
+	}
+
+	return 0;
+
+err_remove_file:
+	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+	return ret;
+}
+
+static int jz4740_hwmon_remove(struct platform_device *pdev)
+{
+	struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(hwmon->hwmon);
+	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+
+	return 0;
+}
+
+static struct platform_driver jz4740_hwmon_driver = {
+	.probe	= jz4740_hwmon_probe,
+	.remove = jz4740_hwmon_remove,
+	.driver = {
+		.name = "jz4740-hwmon",
+	},
+};
+
+module_platform_driver(jz4740_hwmon_driver);
+
+MODULE_DESCRIPTION("JZ4740 SoC HWMON driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:jz4740-hwmon");
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
new file mode 100644
index 0000000..9cdfde6
--- /dev/null
+++ b/drivers/hwmon/k10temp.c
@@ -0,0 +1,227 @@
+/*
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h processor hardware monitoring
+ *
+ * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <asm/processor.h>
+
+MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL");
+
+static bool force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
+
+/* Provide lock for writing to NB_SMU_IND_ADDR */
+static DEFINE_MUTEX(nb_smu_ind_mutex);
+
+/* CPUID function 0x80000001, ebx */
+#define CPUID_PKGTYPE_MASK	0xf0000000
+#define CPUID_PKGTYPE_F		0x00000000
+#define CPUID_PKGTYPE_AM2R2_AM3	0x10000000
+
+/* DRAM controller (PCI function 2) */
+#define REG_DCT0_CONFIG_HIGH		0x094
+#define  DDR3_MODE			0x00000100
+
+/* miscellaneous (PCI function 3) */
+#define REG_HARDWARE_THERMAL_CONTROL	0x64
+#define  HTC_ENABLE			0x00000001
+
+#define REG_REPORTED_TEMPERATURE	0xa4
+
+#define REG_NORTHBRIDGE_CAPABILITIES	0xe8
+#define  NB_CAP_HTC			0x00000400
+
+/*
+ * For F15h M60h, functionality of REG_REPORTED_TEMPERATURE
+ * has been moved to D0F0xBC_xD820_0CA4 [Reported Temperature
+ * Control]
+ */
+#define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET	0xd8200ca4
+
+static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn,
+				  int offset, u32 *val)
+{
+	mutex_lock(&nb_smu_ind_mutex);
+	pci_bus_write_config_dword(pdev->bus, devfn,
+				   0xb8, offset);
+	pci_bus_read_config_dword(pdev->bus, devfn,
+				  0xbc, val);
+	mutex_unlock(&nb_smu_ind_mutex);
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	u32 regval;
+	struct pci_dev *pdev = dev_get_drvdata(dev);
+
+	if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model == 0x60) {
+		amd_nb_smu_index_read(pdev, PCI_DEVFN(0, 0),
+				      F15H_M60H_REPORTED_TEMP_CTRL_OFFSET,
+				      &regval);
+	} else {
+		pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, &regval);
+	}
+	return sprintf(buf, "%u\n", (regval >> 21) * 125);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", 70 * 1000);
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int show_hyst = attr->index;
+	u32 regval;
+	int value;
+
+	pci_read_config_dword(dev_get_drvdata(dev),
+			      REG_HARDWARE_THERMAL_CONTROL, &regval);
+	value = ((regval >> 16) & 0x7f) * 500 + 52000;
+	if (show_hyst)
+		value -= ((regval >> 24) & 0xf) * 500;
+	return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1);
+
+static umode_t k10temp_is_visible(struct kobject *kobj,
+				  struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pci_dev *pdev = dev_get_drvdata(dev);
+
+	if (index >= 2) {
+		u32 reg_caps, reg_htc;
+
+		pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES,
+				      &reg_caps);
+		pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL,
+				      &reg_htc);
+		if (!(reg_caps & NB_CAP_HTC) || !(reg_htc & HTC_ENABLE))
+			return 0;
+	}
+	return attr->mode;
+}
+
+static struct attribute *k10temp_attrs[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group k10temp_group = {
+	.attrs = k10temp_attrs,
+	.is_visible = k10temp_is_visible,
+};
+__ATTRIBUTE_GROUPS(k10temp);
+
+static bool has_erratum_319(struct pci_dev *pdev)
+{
+	u32 pkg_type, reg_dram_cfg;
+
+	if (boot_cpu_data.x86 != 0x10)
+		return false;
+
+	/*
+	 * Erratum 319: The thermal sensor of Socket F/AM2+ processors
+	 *              may be unreliable.
+	 */
+	pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK;
+	if (pkg_type == CPUID_PKGTYPE_F)
+		return true;
+	if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3)
+		return false;
+
+	/* DDR3 memory implies socket AM3, which is good */
+	pci_bus_read_config_dword(pdev->bus,
+				  PCI_DEVFN(PCI_SLOT(pdev->devfn), 2),
+				  REG_DCT0_CONFIG_HIGH, &reg_dram_cfg);
+	if (reg_dram_cfg & DDR3_MODE)
+		return false;
+
+	/*
+	 * Unfortunately it is possible to run a socket AM3 CPU with DDR2
+	 * memory. We blacklist all the cores which do exist in socket AM2+
+	 * format. It still isn't perfect, as RB-C2 cores exist in both AM2+
+	 * and AM3 formats, but that's the best we can do.
+	 */
+	return boot_cpu_data.x86_model < 4 ||
+	       (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2);
+}
+
+static int k10temp_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	int unreliable = has_erratum_319(pdev);
+	struct device *dev = &pdev->dev;
+	struct device *hwmon_dev;
+
+	if (unreliable) {
+		if (!force) {
+			dev_err(dev,
+				"unreliable CPU thermal sensor; monitoring disabled\n");
+			return -ENODEV;
+		}
+		dev_warn(dev,
+			 "unreliable CPU thermal sensor; check erratum 319\n");
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", pdev,
+							   k10temp_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct pci_device_id k10temp_id_table[] = {
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+	{}
+};
+MODULE_DEVICE_TABLE(pci, k10temp_id_table);
+
+static struct pci_driver k10temp_driver = {
+	.name = "k10temp",
+	.id_table = k10temp_id_table,
+	.probe = k10temp_probe,
+};
+
+module_pci_driver(k10temp_driver);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
new file mode 100644
index 0000000..734d55d
--- /dev/null
+++ b/drivers/hwmon/k8temp.c
@@ -0,0 +1,334 @@
+/*
+ * k8temp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2006 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Inspired from the w83785 and amd756 drivers.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/processor.h>
+
+#define TEMP_FROM_REG(val)	(((((val) >> 16) & 0xff) - 49) * 1000)
+#define REG_TEMP	0xe4
+#define SEL_PLACE	0x40
+#define SEL_CORE	0x04
+
+struct k8temp_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	const char *name;
+	char valid;		/* zero until following fields are valid */
+	unsigned long last_updated;	/* in jiffies */
+
+	/* registers values */
+	u8 sensorsp;		/* sensor presence bits - SEL_CORE, SEL_PLACE */
+	u32 temp[2][2];		/* core, place */
+	u8 swap_core_select;    /* meaning of SEL_CORE is inverted */
+	u32 temp_offset;
+};
+
+static struct k8temp_data *k8temp_update_device(struct device *dev)
+{
+	struct k8temp_data *data = dev_get_drvdata(dev);
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid
+	    || time_after(jiffies, data->last_updated + HZ)) {
+		pci_read_config_byte(pdev, REG_TEMP, &tmp);
+		tmp &= ~(SEL_PLACE | SEL_CORE);	/* Select sensor 0, core0 */
+		pci_write_config_byte(pdev, REG_TEMP, tmp);
+		pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
+
+		if (data->sensorsp & SEL_PLACE) {
+			tmp |= SEL_PLACE;	/* Select sensor 1, core0 */
+			pci_write_config_byte(pdev, REG_TEMP, tmp);
+			pci_read_config_dword(pdev, REG_TEMP,
+					      &data->temp[0][1]);
+		}
+
+		if (data->sensorsp & SEL_CORE) {
+			tmp &= ~SEL_PLACE;	/* Select sensor 0, core1 */
+			tmp |= SEL_CORE;
+			pci_write_config_byte(pdev, REG_TEMP, tmp);
+			pci_read_config_dword(pdev, REG_TEMP,
+					      &data->temp[1][0]);
+
+			if (data->sensorsp & SEL_PLACE) {
+				tmp |= SEL_PLACE; /* Select sensor 1, core1 */
+				pci_write_config_byte(pdev, REG_TEMP, tmp);
+				pci_read_config_dword(pdev, REG_TEMP,
+						      &data->temp[1][1]);
+			}
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct k8temp_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr =
+	    to_sensor_dev_attr_2(devattr);
+	int core = attr->nr;
+	int place = attr->index;
+	int temp;
+	struct k8temp_data *data = k8temp_update_device(dev);
+
+	if (data->swap_core_select && (data->sensorsp & SEL_CORE))
+		core = core ? 0 : 1;
+
+	temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+/* core, place */
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static const struct pci_device_id k8temp_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
+	{ 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, k8temp_ids);
+
+static int is_rev_g_desktop(u8 model)
+{
+	u32 brandidx;
+
+	if (model < 0x69)
+		return 0;
+
+	if (model == 0xc1 || model == 0x6c || model == 0x7c)
+		return 0;
+
+	/*
+	 * Differentiate between AM2 and ASB1.
+	 * See "Constructing the processor Name String" in "Revision
+	 * Guide for AMD NPT Family 0Fh Processors" (33610).
+	 */
+	brandidx = cpuid_ebx(0x80000001);
+	brandidx = (brandidx >> 9) & 0x1f;
+
+	/* Single core */
+	if ((model == 0x6f || model == 0x7f) &&
+	    (brandidx == 0x7 || brandidx == 0x9 || brandidx == 0xc))
+		return 0;
+
+	/* Dual core */
+	if (model == 0x6b &&
+	    (brandidx == 0xb || brandidx == 0xc))
+		return 0;
+
+	return 1;
+}
+
+static int k8temp_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *id)
+{
+	int err;
+	u8 scfg;
+	u32 temp;
+	u8 model, stepping;
+	struct k8temp_data *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	model = boot_cpu_data.x86_model;
+	stepping = boot_cpu_data.x86_mask;
+
+	/* feature available since SH-C0, exclude older revisions */
+	if ((model == 4 && stepping == 0) ||
+	    (model == 5 && stepping <= 1))
+		return -ENODEV;
+
+	/*
+	 * AMD NPT family 0fh, i.e. RevF and RevG:
+	 * meaning of SEL_CORE bit is inverted
+	 */
+	if (model >= 0x40) {
+		data->swap_core_select = 1;
+		dev_warn(&pdev->dev,
+			 "Temperature readouts might be wrong - check erratum #141\n");
+	}
+
+	/*
+	 * RevG desktop CPUs (i.e. no socket S1G1 or ASB1 parts) need
+	 * additional offset, otherwise reported temperature is below
+	 * ambient temperature
+	 */
+	if (is_rev_g_desktop(model))
+		data->temp_offset = 21000;
+
+	pci_read_config_byte(pdev, REG_TEMP, &scfg);
+	scfg &= ~(SEL_PLACE | SEL_CORE);	/* Select sensor 0, core0 */
+	pci_write_config_byte(pdev, REG_TEMP, scfg);
+	pci_read_config_byte(pdev, REG_TEMP, &scfg);
+
+	if (scfg & (SEL_PLACE | SEL_CORE)) {
+		dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
+		return -ENODEV;
+	}
+
+	scfg |= (SEL_PLACE | SEL_CORE);
+	pci_write_config_byte(pdev, REG_TEMP, scfg);
+
+	/* now we know if we can change core and/or sensor */
+	pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp);
+
+	if (data->sensorsp & SEL_PLACE) {
+		scfg &= ~SEL_CORE;	/* Select sensor 1, core0 */
+		pci_write_config_byte(pdev, REG_TEMP, scfg);
+		pci_read_config_dword(pdev, REG_TEMP, &temp);
+		scfg |= SEL_CORE;	/* prepare for next selection */
+		if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */
+			data->sensorsp &= ~SEL_PLACE;
+	}
+
+	if (data->sensorsp & SEL_CORE) {
+		scfg &= ~SEL_PLACE;	/* Select sensor 0, core1 */
+		pci_write_config_byte(pdev, REG_TEMP, scfg);
+		pci_read_config_dword(pdev, REG_TEMP, &temp);
+		if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */
+			data->sensorsp &= ~SEL_CORE;
+	}
+
+	data->name = "k8temp";
+	mutex_init(&data->update_lock);
+	pci_set_drvdata(pdev, data);
+
+	/* Register sysfs hooks */
+	err = device_create_file(&pdev->dev,
+			   &sensor_dev_attr_temp1_input.dev_attr);
+	if (err)
+		goto exit_remove;
+
+	/* sensor can be changed and reports something */
+	if (data->sensorsp & SEL_PLACE) {
+		err = device_create_file(&pdev->dev,
+				   &sensor_dev_attr_temp2_input.dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+
+	/* core can be changed and reports something */
+	if (data->sensorsp & SEL_CORE) {
+		err = device_create_file(&pdev->dev,
+				   &sensor_dev_attr_temp3_input.dev_attr);
+		if (err)
+			goto exit_remove;
+		if (data->sensorsp & SEL_PLACE) {
+			err = device_create_file(&pdev->dev,
+					   &sensor_dev_attr_temp4_input.
+					   dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	err = device_create_file(&pdev->dev, &dev_attr_name);
+	if (err)
+		goto exit_remove;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp1_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp2_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp3_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp4_input.dev_attr);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	return err;
+}
+
+static void k8temp_remove(struct pci_dev *pdev)
+{
+	struct k8temp_data *data = pci_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp1_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp2_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp3_input.dev_attr);
+	device_remove_file(&pdev->dev,
+			   &sensor_dev_attr_temp4_input.dev_attr);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+}
+
+static struct pci_driver k8temp_driver = {
+	.name = "k8temp",
+	.id_table = k8temp_ids,
+	.probe = k8temp_probe,
+	.remove = k8temp_remove,
+};
+
+module_pci_driver(k8temp_driver);
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
+MODULE_DESCRIPTION("AMD K8 core temperature monitor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c
new file mode 100644
index 0000000..84d791b
--- /dev/null
+++ b/drivers/hwmon/lineage-pem.c
@@ -0,0 +1,547 @@
+/*
+ * Driver for Lineage Compact Power Line series of power entry modules.
+ *
+ * Copyright (C) 2010, 2011 Ericsson AB.
+ *
+ * Documentation:
+ *  http://www.lineagepower.com/oem/pdf/CPLI2C.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/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/jiffies.h>
+
+/*
+ * This driver supports various Lineage Compact Power Line DC/DC and AC/DC
+ * converters such as CP1800, CP2000AC, CP2000DC, CP2100DC, and others.
+ *
+ * The devices are nominally PMBus compliant. However, most standard PMBus
+ * commands are not supported. Specifically, all hardware monitoring and
+ * status reporting commands are non-standard. For this reason, a standard
+ * PMBus driver can not be used.
+ *
+ * All Lineage CPL devices have a built-in I2C bus master selector (PCA9541).
+ * To ensure device access, this driver should only be used as client driver
+ * to the pca9541 I2C master selector driver.
+ */
+
+/* Command codes */
+#define PEM_OPERATION		0x01
+#define PEM_CLEAR_INFO_FLAGS	0x03
+#define PEM_VOUT_COMMAND	0x21
+#define PEM_VOUT_OV_FAULT_LIMIT	0x40
+#define PEM_READ_DATA_STRING	0xd0
+#define PEM_READ_INPUT_STRING	0xdc
+#define PEM_READ_FIRMWARE_REV	0xdd
+#define PEM_READ_RUN_TIMER	0xde
+#define PEM_FAN_HI_SPEED	0xdf
+#define PEM_FAN_NORMAL_SPEED	0xe0
+#define PEM_READ_FAN_SPEED	0xe1
+
+/* offsets in data string */
+#define PEM_DATA_STATUS_2	0
+#define PEM_DATA_STATUS_1	1
+#define PEM_DATA_ALARM_2	2
+#define PEM_DATA_ALARM_1	3
+#define PEM_DATA_VOUT_LSB	4
+#define PEM_DATA_VOUT_MSB	5
+#define PEM_DATA_CURRENT	6
+#define PEM_DATA_TEMP		7
+
+/* Virtual entries, to report constants */
+#define PEM_DATA_TEMP_MAX	10
+#define PEM_DATA_TEMP_CRIT	11
+
+/* offsets in input string */
+#define PEM_INPUT_VOLTAGE	0
+#define PEM_INPUT_POWER_LSB	1
+#define PEM_INPUT_POWER_MSB	2
+
+/* offsets in fan data */
+#define PEM_FAN_ADJUSTMENT	0
+#define PEM_FAN_FAN1		1
+#define PEM_FAN_FAN2		2
+#define PEM_FAN_FAN3		3
+
+/* Status register bits */
+#define STS1_OUTPUT_ON		(1 << 0)
+#define STS1_LEDS_FLASHING	(1 << 1)
+#define STS1_EXT_FAULT		(1 << 2)
+#define STS1_SERVICE_LED_ON	(1 << 3)
+#define STS1_SHUTDOWN_OCCURRED	(1 << 4)
+#define STS1_INT_FAULT		(1 << 5)
+#define STS1_ISOLATION_TEST_OK	(1 << 6)
+
+#define STS2_ENABLE_PIN_HI	(1 << 0)
+#define STS2_DATA_OUT_RANGE	(1 << 1)
+#define STS2_RESTARTED_OK	(1 << 1)
+#define STS2_ISOLATION_TEST_FAIL (1 << 3)
+#define STS2_HIGH_POWER_CAP	(1 << 4)
+#define STS2_INVALID_INSTR	(1 << 5)
+#define STS2_WILL_RESTART	(1 << 6)
+#define STS2_PEC_ERR		(1 << 7)
+
+/* Alarm register bits */
+#define ALRM1_VIN_OUT_LIMIT	(1 << 0)
+#define ALRM1_VOUT_OUT_LIMIT	(1 << 1)
+#define ALRM1_OV_VOLT_SHUTDOWN	(1 << 2)
+#define ALRM1_VIN_OVERCURRENT	(1 << 3)
+#define ALRM1_TEMP_WARNING	(1 << 4)
+#define ALRM1_TEMP_SHUTDOWN	(1 << 5)
+#define ALRM1_PRIMARY_FAULT	(1 << 6)
+#define ALRM1_POWER_LIMIT	(1 << 7)
+
+#define ALRM2_5V_OUT_LIMIT	(1 << 1)
+#define ALRM2_TEMP_FAULT	(1 << 2)
+#define ALRM2_OV_LOW		(1 << 3)
+#define ALRM2_DCDC_TEMP_HIGH	(1 << 4)
+#define ALRM2_PRI_TEMP_HIGH	(1 << 5)
+#define ALRM2_NO_PRIMARY	(1 << 6)
+#define ALRM2_FAN_FAULT		(1 << 7)
+
+#define FIRMWARE_REV_LEN	4
+#define DATA_STRING_LEN		9
+#define INPUT_STRING_LEN	5	/* 4 for most devices	*/
+#define FAN_SPEED_LEN		5
+
+struct pem_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[4];
+
+	struct mutex update_lock;
+	bool valid;
+	bool fans_supported;
+	int input_length;
+	unsigned long last_updated;	/* in jiffies */
+
+	u8 firmware_rev[FIRMWARE_REV_LEN];
+	u8 data_string[DATA_STRING_LEN];
+	u8 input_string[INPUT_STRING_LEN];
+	u8 fan_speed[FAN_SPEED_LEN];
+};
+
+static int pem_read_block(struct i2c_client *client, u8 command, u8 *data,
+			  int data_len)
+{
+	u8 block_buffer[I2C_SMBUS_BLOCK_MAX];
+	int result;
+
+	result = i2c_smbus_read_block_data(client, command, block_buffer);
+	if (unlikely(result < 0))
+		goto abort;
+	if (unlikely(result == 0xff || result != data_len)) {
+		result = -EIO;
+		goto abort;
+	}
+	memcpy(data, block_buffer, data_len);
+	result = 0;
+abort:
+	return result;
+}
+
+static struct pem_data *pem_update_device(struct device *dev)
+{
+	struct pem_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct pem_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		int result;
+
+		/* Read data string */
+		result = pem_read_block(client, PEM_READ_DATA_STRING,
+					data->data_string,
+					sizeof(data->data_string));
+		if (unlikely(result < 0)) {
+			ret = ERR_PTR(result);
+			goto abort;
+		}
+
+		/* Read input string */
+		if (data->input_length) {
+			result = pem_read_block(client, PEM_READ_INPUT_STRING,
+						data->input_string,
+						data->input_length);
+			if (unlikely(result < 0)) {
+				ret = ERR_PTR(result);
+				goto abort;
+			}
+		}
+
+		/* Read fan speeds */
+		if (data->fans_supported) {
+			result = pem_read_block(client, PEM_READ_FAN_SPEED,
+						data->fan_speed,
+						sizeof(data->fan_speed));
+			if (unlikely(result < 0)) {
+				ret = ERR_PTR(result);
+				goto abort;
+			}
+		}
+
+		i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static long pem_get_data(u8 *data, int len, int index)
+{
+	long val;
+
+	switch (index) {
+	case PEM_DATA_VOUT_LSB:
+		val = (data[index] + (data[index+1] << 8)) * 5 / 2;
+		break;
+	case PEM_DATA_CURRENT:
+		val = data[index] * 200;
+		break;
+	case PEM_DATA_TEMP:
+		val = data[index] * 1000;
+		break;
+	case PEM_DATA_TEMP_MAX:
+		val = 97 * 1000;	/* 97 degrees C per datasheet */
+		break;
+	case PEM_DATA_TEMP_CRIT:
+		val = 107 * 1000;	/* 107 degrees C per datasheet */
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		val = 0;
+	}
+	return val;
+}
+
+static long pem_get_input(u8 *data, int len, int index)
+{
+	long val;
+
+	switch (index) {
+	case PEM_INPUT_VOLTAGE:
+		if (len == INPUT_STRING_LEN)
+			val = (data[index] + (data[index+1] << 8) - 75) * 1000;
+		else
+			val = (data[index] - 75) * 1000;
+		break;
+	case PEM_INPUT_POWER_LSB:
+		if (len == INPUT_STRING_LEN)
+			index++;
+		val = (data[index] + (data[index+1] << 8)) * 1000000L;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		val = 0;
+	}
+	return val;
+}
+
+static long pem_get_fan(u8 *data, int len, int index)
+{
+	long val;
+
+	switch (index) {
+	case PEM_FAN_FAN1:
+	case PEM_FAN_FAN2:
+	case PEM_FAN_FAN3:
+		val = data[index] * 100;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		val = 0;
+	}
+	return val;
+}
+
+/*
+ * Show boolean, either a fault or an alarm.
+ * .nr points to the register, .index is the bit mask to check
+ */
+static ssize_t pem_show_bool(struct device *dev,
+			     struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+	struct pem_data *data = pem_update_device(dev);
+	u8 status;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	status = data->data_string[attr->nr] & attr->index;
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!status);
+}
+
+static ssize_t pem_show_data(struct device *dev, struct device_attribute *da,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pem_data *data = pem_update_device(dev);
+	long value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = pem_get_data(data->data_string, sizeof(data->data_string),
+			     attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+static ssize_t pem_show_input(struct device *dev, struct device_attribute *da,
+			      char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pem_data *data = pem_update_device(dev);
+	long value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = pem_get_input(data->input_string, sizeof(data->input_string),
+			      attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+static ssize_t pem_show_fan(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pem_data *data = pem_update_device(dev);
+	long value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = pem_get_fan(data->fan_speed, sizeof(data->fan_speed),
+			    attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, pem_show_data, NULL,
+			  PEM_DATA_VOUT_LSB);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_VOUT_OUT_LIMIT);
+static SENSOR_DEVICE_ATTR_2(in1_crit_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_OV_VOLT_SHUTDOWN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, pem_show_input, NULL,
+			  PEM_INPUT_VOLTAGE);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1,
+			    ALRM1_VIN_OUT_LIMIT | ALRM1_PRIMARY_FAULT);
+
+/* Currents */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, pem_show_data, NULL,
+			  PEM_DATA_CURRENT);
+static SENSOR_DEVICE_ATTR_2(curr1_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_VIN_OVERCURRENT);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, pem_show_input, NULL,
+			  PEM_INPUT_POWER_LSB);
+static SENSOR_DEVICE_ATTR_2(power1_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_POWER_LIMIT);
+
+/* Fans */
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, pem_show_fan, NULL,
+			  PEM_FAN_FAN1);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, pem_show_fan, NULL,
+			  PEM_FAN_FAN2);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, pem_show_fan, NULL,
+			  PEM_FAN_FAN3);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_2, ALRM2_FAN_FAULT);
+
+/* Temperatures */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, pem_show_data, NULL,
+			  PEM_DATA_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, pem_show_data, NULL,
+			  PEM_DATA_TEMP_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, pem_show_data, NULL,
+			  PEM_DATA_TEMP_CRIT);
+static SENSOR_DEVICE_ATTR_2(temp1_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_TEMP_WARNING);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_1, ALRM1_TEMP_SHUTDOWN);
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, pem_show_bool, NULL,
+			    PEM_DATA_ALARM_2, ALRM2_TEMP_FAULT);
+
+static struct attribute *pem_attributes[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_power1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+
+	NULL,
+};
+
+static const struct attribute_group pem_group = {
+	.attrs = pem_attributes,
+};
+
+static struct attribute *pem_input_attributes[] = {
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group pem_input_group = {
+	.attrs = pem_input_attributes,
+};
+
+static struct attribute *pem_fan_attributes[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group pem_fan_group = {
+	.attrs = pem_fan_attributes,
+};
+
+static int pem_probe(struct i2c_client *client,
+		     const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct pem_data *data;
+	int ret, idx = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_DATA
+				     | I2C_FUNC_SMBUS_WRITE_BYTE))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/*
+	 * We use the next two commands to determine if the device is really
+	 * there.
+	 */
+	ret = pem_read_block(client, PEM_READ_FIRMWARE_REV,
+			     data->firmware_rev, sizeof(data->firmware_rev));
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
+	if (ret < 0)
+		return ret;
+
+	dev_info(dev, "Firmware revision %d.%d.%d\n",
+		 data->firmware_rev[0], data->firmware_rev[1],
+		 data->firmware_rev[2]);
+
+	/* sysfs hooks */
+	data->groups[idx++] = &pem_group;
+
+	/*
+	 * Check if input readings are supported.
+	 * This is the case if we can read input data,
+	 * and if the returned data is not all zeros.
+	 * Note that input alarms are always supported.
+	 */
+	ret = pem_read_block(client, PEM_READ_INPUT_STRING,
+			     data->input_string,
+			     sizeof(data->input_string) - 1);
+	if (!ret && (data->input_string[0] || data->input_string[1] ||
+		     data->input_string[2]))
+		data->input_length = sizeof(data->input_string) - 1;
+	else if (ret < 0) {
+		/* Input string is one byte longer for some devices */
+		ret = pem_read_block(client, PEM_READ_INPUT_STRING,
+				    data->input_string,
+				    sizeof(data->input_string));
+		if (!ret && (data->input_string[0] || data->input_string[1] ||
+			    data->input_string[2] || data->input_string[3]))
+			data->input_length = sizeof(data->input_string);
+	}
+
+	if (data->input_length)
+		data->groups[idx++] = &pem_input_group;
+
+	/*
+	 * Check if fan speed readings are supported.
+	 * This is the case if we can read fan speed data,
+	 * and if the returned data is not all zeros.
+	 * Note that the fan alarm is always supported.
+	 */
+	ret = pem_read_block(client, PEM_READ_FAN_SPEED,
+			     data->fan_speed,
+			     sizeof(data->fan_speed));
+	if (!ret && (data->fan_speed[0] || data->fan_speed[1] ||
+		     data->fan_speed[2] || data->fan_speed[3])) {
+		data->fans_supported = true;
+		data->groups[idx++] = &pem_fan_group;
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id pem_id[] = {
+	{"lineage_pem", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, pem_id);
+
+static struct i2c_driver pem_driver = {
+	.driver = {
+		   .name = "lineage_pem",
+		   },
+	.probe = pem_probe,
+	.id_table = pem_id,
+};
+
+module_i2c_driver(pem_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("Lineage CPL PEM hardware monitoring driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
new file mode 100644
index 0000000..33bfdb4
--- /dev/null
+++ b/drivers/hwmon/lm63.c
@@ -0,0 +1,1169 @@
+/*
+ * lm63.c - driver for the National Semiconductor LM63 temperature sensor
+ *          with integrated fan control
+ * Copyright (C) 2004-2008  Jean Delvare <jdelvare@suse.de>
+ * Based on the lm90 driver.
+ *
+ * The LM63 is a sensor chip made by National Semiconductor. It measures
+ * two temperatures (its own and one external one) and the speed of one
+ * fan, those speed it can additionally control. Complete datasheet can be
+ * obtained from National's website at:
+ *   http://www.national.com/pf/LM/LM63.html
+ *
+ * The LM63 is basically an LM86 with fan speed monitoring and control
+ * capabilities added. It misses some of the LM86 features though:
+ *  - No low limit for local temperature.
+ *  - No critical limit for local temperature.
+ *  - Critical limit for remote temperature can be changed only once. We
+ *    will consider that the critical limit is read-only.
+ *
+ * The datasheet isn't very clear about what the tachometer reading is.
+ * I had a explanation from National Semiconductor though. The two lower
+ * bits of the read value have to be masked out. The value is still 16 bit
+ * in width.
+ *
+ * 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-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+/*
+ * Addresses to scan
+ * Address is fully defined internally and cannot be changed except for
+ * LM64 which has one pin dedicated to address selection.
+ * LM63 and LM96163 have address 0x4c.
+ * LM64 can have address 0x18 or 0x4e.
+ */
+
+static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
+
+/*
+ * The LM63 registers
+ */
+
+#define LM63_REG_CONFIG1		0x03
+#define LM63_REG_CONVRATE		0x04
+#define LM63_REG_CONFIG2		0xBF
+#define LM63_REG_CONFIG_FAN		0x4A
+
+#define LM63_REG_TACH_COUNT_MSB		0x47
+#define LM63_REG_TACH_COUNT_LSB		0x46
+#define LM63_REG_TACH_LIMIT_MSB		0x49
+#define LM63_REG_TACH_LIMIT_LSB		0x48
+
+#define LM63_REG_PWM_VALUE		0x4C
+#define LM63_REG_PWM_FREQ		0x4D
+#define LM63_REG_LUT_TEMP_HYST		0x4F
+#define LM63_REG_LUT_TEMP(nr)		(0x50 + 2 * (nr))
+#define LM63_REG_LUT_PWM(nr)		(0x51 + 2 * (nr))
+
+#define LM63_REG_LOCAL_TEMP		0x00
+#define LM63_REG_LOCAL_HIGH		0x05
+
+#define LM63_REG_REMOTE_TEMP_MSB	0x01
+#define LM63_REG_REMOTE_TEMP_LSB	0x10
+#define LM63_REG_REMOTE_OFFSET_MSB	0x11
+#define LM63_REG_REMOTE_OFFSET_LSB	0x12
+#define LM63_REG_REMOTE_HIGH_MSB	0x07
+#define LM63_REG_REMOTE_HIGH_LSB	0x13
+#define LM63_REG_REMOTE_LOW_MSB		0x08
+#define LM63_REG_REMOTE_LOW_LSB		0x14
+#define LM63_REG_REMOTE_TCRIT		0x19
+#define LM63_REG_REMOTE_TCRIT_HYST	0x21
+
+#define LM63_REG_ALERT_STATUS		0x02
+#define LM63_REG_ALERT_MASK		0x16
+
+#define LM63_REG_MAN_ID			0xFE
+#define LM63_REG_CHIP_ID		0xFF
+
+#define LM96163_REG_TRUTHERM		0x30
+#define LM96163_REG_REMOTE_TEMP_U_MSB	0x31
+#define LM96163_REG_REMOTE_TEMP_U_LSB	0x32
+#define LM96163_REG_CONFIG_ENHANCED	0x45
+
+#define LM63_MAX_CONVRATE		9
+
+#define LM63_MAX_CONVRATE_HZ		32
+#define LM96163_MAX_CONVRATE_HZ		26
+
+/*
+ * Conversions and various macros
+ * For tachometer counts, the LM63 uses 16-bit values.
+ * For local temperature and high limit, remote critical limit and hysteresis
+ * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
+ * For remote temperature, low and high limits, it uses signed 11-bit values
+ * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
+ * For LM64 the actual remote diode temperature is 16 degree Celsius higher
+ * than the register reading. Remote temperature setpoints have to be
+ * adapted accordingly.
+ */
+
+#define FAN_FROM_REG(reg)	((reg) == 0xFFFC || (reg) == 0 ? 0 : \
+				 5400000 / (reg))
+#define FAN_TO_REG(val)		((val) <= 82 ? 0xFFFC : \
+				 (5400000 / (val)) & 0xFFFC)
+#define TEMP8_FROM_REG(reg)	((reg) * 1000)
+#define TEMP8_TO_REG(val)	DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
+							    127000), 1000)
+#define TEMP8U_TO_REG(val)	DIV_ROUND_CLOSEST(clamp_val((val), 0, \
+							    255000), 1000)
+#define TEMP11_FROM_REG(reg)	((reg) / 32 * 125)
+#define TEMP11_TO_REG(val)	(DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
+							     127875), 125) * 32)
+#define TEMP11U_TO_REG(val)	(DIV_ROUND_CLOSEST(clamp_val((val), 0, \
+							     255875), 125) * 32)
+#define HYST_TO_REG(val)	DIV_ROUND_CLOSEST(clamp_val((val), 0, 127000), \
+						  1000)
+
+#define UPDATE_INTERVAL(max, rate) \
+			((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
+
+enum chips { lm63, lm64, lm96163 };
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm63_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	const struct attribute_group *groups[5];
+	char valid; /* zero until following fields are valid */
+	char lut_valid; /* zero until lut fields are valid */
+	unsigned long last_updated; /* in jiffies */
+	unsigned long lut_last_updated; /* in jiffies */
+	enum chips kind;
+	int temp2_offset;
+
+	int update_interval;	/* in milliseconds */
+	int max_convrate_hz;
+	int lut_size;		/* 8 or 12 */
+
+	/* registers values */
+	u8 config, config_fan;
+	u16 fan[2];	/* 0: input
+			   1: low limit */
+	u8 pwm1_freq;
+	u8 pwm1[13];	/* 0: current output
+			   1-12: lookup table */
+	s8 temp8[15];	/* 0: local input
+			   1: local high limit
+			   2: remote critical limit
+			   3-14: lookup table */
+	s16 temp11[4];	/* 0: remote input
+			   1: remote low limit
+			   2: remote high limit
+			   3: remote offset */
+	u16 temp11u;	/* remote input (unsigned) */
+	u8 temp2_crit_hyst;
+	u8 lut_temp_hyst;
+	u8 alarms;
+	bool pwm_highres;
+	bool lut_temp_highres;
+	bool remote_unsigned; /* true if unsigned remote upper limits */
+	bool trutherm;
+};
+
+static inline int temp8_from_reg(struct lm63_data *data, int nr)
+{
+	if (data->remote_unsigned)
+		return TEMP8_FROM_REG((u8)data->temp8[nr]);
+	return TEMP8_FROM_REG(data->temp8[nr]);
+}
+
+static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
+{
+	return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
+}
+
+static inline int lut_temp_to_reg(struct lm63_data *data, long val)
+{
+	val -= data->temp2_offset;
+	if (data->lut_temp_highres)
+		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500);
+	else
+		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
+}
+
+/*
+ * Update the lookup table register cache.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_update_lut(struct lm63_data *data)
+{
+	struct i2c_client *client = data->client;
+	int i;
+
+	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
+	    !data->lut_valid) {
+		for (i = 0; i < data->lut_size; i++) {
+			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+					    LM63_REG_LUT_PWM(i));
+			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+					     LM63_REG_LUT_TEMP(i));
+		}
+		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+				      LM63_REG_LUT_TEMP_HYST);
+
+		data->lut_last_updated = jiffies;
+		data->lut_valid = 1;
+	}
+}
+
+static struct lm63_data *lm63_update_device(struct device *dev)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long next_update;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated +
+		      msecs_to_jiffies(data->update_interval);
+	if (time_after(jiffies, next_update) || !data->valid) {
+		if (data->config & 0x04) { /* tachometer enabled  */
+			/* order matters for fan1_input */
+			data->fan[0] = i2c_smbus_read_byte_data(client,
+				       LM63_REG_TACH_COUNT_LSB) & 0xFC;
+			data->fan[0] |= i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_COUNT_MSB) << 8;
+			data->fan[1] = (i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_LIMIT_LSB) & 0xFC)
+				     | (i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_LIMIT_MSB) << 8);
+		}
+
+		data->pwm1_freq = i2c_smbus_read_byte_data(client,
+				  LM63_REG_PWM_FREQ);
+		if (data->pwm1_freq == 0)
+			data->pwm1_freq = 1;
+		data->pwm1[0] = i2c_smbus_read_byte_data(client,
+				LM63_REG_PWM_VALUE);
+
+		data->temp8[0] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_LOCAL_TEMP);
+		data->temp8[1] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_LOCAL_HIGH);
+
+		/* order matters for temp2_input */
+		data->temp11[0] = i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_TEMP_MSB) << 8;
+		data->temp11[0] |= i2c_smbus_read_byte_data(client,
+				   LM63_REG_REMOTE_TEMP_LSB);
+		data->temp11[1] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_LOW_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_LOW_LSB);
+		data->temp11[2] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_HIGH_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_HIGH_LSB);
+		data->temp11[3] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_OFFSET_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_OFFSET_LSB);
+
+		if (data->kind == lm96163)
+			data->temp11u = (i2c_smbus_read_byte_data(client,
+					LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
+				      | i2c_smbus_read_byte_data(client,
+					LM96163_REG_REMOTE_TEMP_U_LSB);
+
+		data->temp8[2] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_REMOTE_TCRIT);
+		data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
+					LM63_REG_REMOTE_TCRIT_HYST);
+
+		data->alarms = i2c_smbus_read_byte_data(client,
+			       LM63_REG_ALERT_STATUS) & 0x7F;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	lm63_update_lut(data);
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Trip points in the lookup table should be in ascending order for both
+ * temperatures and PWM output values.
+ */
+static int lm63_lut_looks_bad(struct device *dev, struct lm63_data *data)
+{
+	int i;
+
+	mutex_lock(&data->update_lock);
+	lm63_update_lut(data);
+
+	for (i = 1; i < data->lut_size; i++) {
+		if (data->pwm1[1 + i - 1] > data->pwm1[1 + i]
+		 || data->temp8[3 + i - 1] > data->temp8[3 + i]) {
+			dev_warn(dev,
+				 "Lookup table doesn't look sane (check entries %d and %d)\n",
+				 i, i + 1);
+			break;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+
+	return i == data->lut_size ? 0 : 1;
+}
+
+/*
+ * Sysfs callback functions and files
+ */
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index]));
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
+		       const char *buf, size_t count)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan[1] = FAN_TO_REG(val);
+	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
+				  data->fan[1] & 0xFF);
+	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
+				  data->fan[1] >> 8);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	int nr = attr->index;
+	int pwm;
+
+	if (data->pwm_highres)
+		pwm = data->pwm1[nr];
+	else
+		pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
+		       255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
+		       (2 * data->pwm1_freq);
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+	u8 reg;
+
+	if (!(data->config_fan & 0x20)) /* register is read-only */
+		return -EPERM;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->pwm1[nr] = data->pwm_highres ? val :
+			(val * data->pwm1_freq * 2 + 127) / 255;
+	i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm1_enable(struct device *dev,
+				struct device_attribute *dummy, char *buf)
+{
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
+}
+
+static ssize_t set_pwm1_enable(struct device *dev,
+			       struct device_attribute *dummy,
+			       const char *buf, size_t count)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val < 1 || val > 2)
+		return -EINVAL;
+
+	/*
+	 * Only let the user switch to automatic mode if the lookup table
+	 * looks sane.
+	 */
+	if (val == 2 && lm63_lut_looks_bad(dev, data))
+		return -EPERM;
+
+	mutex_lock(&data->update_lock);
+	data->config_fan = i2c_smbus_read_byte_data(client,
+						    LM63_REG_CONFIG_FAN);
+	if (val == 1)
+		data->config_fan |= 0x20;
+	else
+		data->config_fan &= ~0x20;
+	i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN,
+				  data->config_fan);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
+ * For remote sensor registers temp2_offset has to be considered,
+ * for local sensor it must not.
+ * So we need separate 8bit accessors for local and remote sensor.
+ */
+static ssize_t show_local_temp8(struct device *dev,
+				struct device_attribute *devattr,
+				char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
+}
+
+static ssize_t show_remote_temp8(struct device *dev,
+				 struct device_attribute *devattr,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index)
+		       + data->temp2_offset);
+}
+
+static ssize_t show_lut_temp(struct device *dev,
+			      struct device_attribute *devattr,
+			      char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+		       + data->temp2_offset);
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long val;
+	int err;
+	int temp;
+	u8 reg;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case 2:
+		reg = LM63_REG_REMOTE_TCRIT;
+		if (data->remote_unsigned)
+			temp = TEMP8U_TO_REG(val - data->temp2_offset);
+		else
+			temp = TEMP8_TO_REG(val - data->temp2_offset);
+		break;
+	case 1:
+		reg = LM63_REG_LOCAL_HIGH;
+		temp = TEMP8_TO_REG(val);
+		break;
+	default:	/* lookup table */
+		reg = LM63_REG_LUT_TEMP(nr - 3);
+		temp = lut_temp_to_reg(data, val);
+	}
+	data->temp8[nr] = temp;
+	i2c_smbus_write_byte_data(client, reg, temp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
+			   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	int nr = attr->index;
+	int temp;
+
+	if (!nr) {
+		/*
+		 * Use unsigned temperature unless its value is zero.
+		 * If it is zero, use signed temperature.
+		 */
+		if (data->temp11u)
+			temp = TEMP11_FROM_REG(data->temp11u);
+		else
+			temp = TEMP11_FROM_REG(data->temp11[nr]);
+	} else {
+		if (data->remote_unsigned && nr == 2)
+			temp = TEMP11_FROM_REG((u16)data->temp11[nr]);
+		else
+			temp = TEMP11_FROM_REG(data->temp11[nr]);
+	}
+	return sprintf(buf, "%d\n", temp + data->temp2_offset);
+}
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	static const u8 reg[6] = {
+		LM63_REG_REMOTE_LOW_MSB,
+		LM63_REG_REMOTE_LOW_LSB,
+		LM63_REG_REMOTE_HIGH_MSB,
+		LM63_REG_REMOTE_HIGH_LSB,
+		LM63_REG_REMOTE_OFFSET_MSB,
+		LM63_REG_REMOTE_OFFSET_LSB,
+	};
+
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+	int nr = attr->index;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (data->remote_unsigned && nr == 2)
+		data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset);
+	else
+		data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
+
+	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
+				  data->temp11[nr] >> 8);
+	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
+				  data->temp11[nr] & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Hysteresis register holds a relative value, while we want to present
+ * an absolute to user-space
+ */
+static ssize_t show_temp2_crit_hyst(struct device *dev,
+				    struct device_attribute *dummy, char *buf)
+{
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
+		       + data->temp2_offset
+		       - TEMP8_FROM_REG(data->temp2_crit_hyst));
+}
+
+static ssize_t show_lut_temp_hyst(struct device *dev,
+				  struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+
+	return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+		       + data->temp2_offset
+		       - TEMP8_FROM_REG(data->lut_temp_hyst));
+}
+
+/*
+ * And now the other way around, user-space provides an absolute
+ * hysteresis value and we have to store a relative one
+ */
+static ssize_t set_temp2_crit_hyst(struct device *dev,
+				   struct device_attribute *dummy,
+				   const char *buf, size_t count)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+	long hyst;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
+	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
+				  HYST_TO_REG(hyst));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Set conversion rate.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_set_convrate(struct lm63_data *data, unsigned int interval)
+{
+	struct i2c_client *client = data->client;
+	unsigned int update_interval;
+	int i;
+
+	/* Shift calculations to avoid rounding errors */
+	interval <<= 6;
+
+	/* find the nearest update rate */
+	update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000
+	  / data->max_convrate_hz;
+	for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1)
+		if (interval >= update_interval * 3 / 4)
+			break;
+
+	i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
+}
+
+static ssize_t show_update_interval(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	lm63_set_convrate(data, clamp_val(val, 0, 100000));
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, data->trutherm ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm63_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int ret;
+	u8 reg;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+	if (val != 1 && val != 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->trutherm = val == 1;
+	reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
+	i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
+				  reg | (data->trutherm ? 0x02 : 0x00));
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+			   char *buf)
+{
+	struct lm63_data *data = lm63_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm63_data *data = lm63_update_device(dev);
+	int bitnr = attr->index;
+
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
+	set_fan, 1);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+	show_pwm1_enable, set_pwm1_enable);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 14);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
+	show_lut_temp_hyst, NULL, 14);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
+	set_temp8, 1);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 2);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 3);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
+	set_temp8, 2);
+static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
+	set_temp2_crit_hyst);
+
+static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+		   set_update_interval);
+
+static struct attribute *lm63_attributes[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&dev_attr_pwm1_enable.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&dev_attr_temp2_crit_hyst.attr,
+
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+
+static struct attribute *lm63_attributes_temp2_type[] = {
+	&dev_attr_temp2_type.attr,
+	NULL
+};
+
+static const struct attribute_group lm63_group_temp2_type = {
+	.attrs = lm63_attributes_temp2_type,
+};
+
+static struct attribute *lm63_attributes_extra_lut[] = {
+	&sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm63_group_extra_lut = {
+	.attrs = lm63_attributes_extra_lut,
+};
+
+/*
+ * On LM63, temp2_crit can be set only once, which should be job
+ * of the bootloader.
+ * On LM64, temp2_crit can always be set.
+ * On LM96163, temp2_crit can be set if bit 1 of the configuration
+ * register is true.
+ */
+static umode_t lm63_attribute_mode(struct kobject *kobj,
+				   struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct lm63_data *data = dev_get_drvdata(dev);
+
+	if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
+	    && (data->kind == lm64 ||
+		(data->kind == lm96163 && (data->config & 0x02))))
+		return attr->mode | S_IWUSR;
+
+	return attr->mode;
+}
+
+static const struct attribute_group lm63_group = {
+	.is_visible = lm63_attribute_mode,
+	.attrs = lm63_attributes,
+};
+
+static struct attribute *lm63_attributes_fan1[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm63_group_fan1 = {
+	.attrs = lm63_attributes_fan1,
+};
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm63_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u8 man_id, chip_id, reg_config1, reg_config2;
+	u8 reg_alert_status, reg_alert_mask;
+	int address = client->addr;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	man_id = i2c_smbus_read_byte_data(client, LM63_REG_MAN_ID);
+	chip_id = i2c_smbus_read_byte_data(client, LM63_REG_CHIP_ID);
+
+	reg_config1 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+	reg_config2 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG2);
+	reg_alert_status = i2c_smbus_read_byte_data(client,
+			   LM63_REG_ALERT_STATUS);
+	reg_alert_mask = i2c_smbus_read_byte_data(client, LM63_REG_ALERT_MASK);
+
+	if (man_id != 0x01 /* National Semiconductor */
+	 || (reg_config1 & 0x18) != 0x00
+	 || (reg_config2 & 0xF8) != 0x00
+	 || (reg_alert_status & 0x20) != 0x00
+	 || (reg_alert_mask & 0xA4) != 0xA4) {
+		dev_dbg(&adapter->dev,
+			"Unsupported chip (man_id=0x%02X, chip_id=0x%02X)\n",
+			man_id, chip_id);
+		return -ENODEV;
+	}
+
+	if (chip_id == 0x41 && address == 0x4c)
+		strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+	else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
+		strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+	else if (chip_id == 0x49 && address == 0x4c)
+		strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
+	else
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ * Ideally we shouldn't have to initialize anything, since the BIOS
+ * should have taken care of everything
+ */
+static void lm63_init_client(struct lm63_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct device *dev = &client->dev;
+	u8 convrate;
+
+	data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+	data->config_fan = i2c_smbus_read_byte_data(client,
+						    LM63_REG_CONFIG_FAN);
+
+	/* Start converting if needed */
+	if (data->config & 0x40) { /* standby */
+		dev_dbg(dev, "Switching to operational mode\n");
+		data->config &= 0xA7;
+		i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
+					  data->config);
+	}
+	/* Tachometer is always enabled on LM64 */
+	if (data->kind == lm64)
+		data->config |= 0x04;
+
+	/* We may need pwm1_freq before ever updating the client data */
+	data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+	if (data->pwm1_freq == 0)
+		data->pwm1_freq = 1;
+
+	switch (data->kind) {
+	case lm63:
+	case lm64:
+		data->max_convrate_hz = LM63_MAX_CONVRATE_HZ;
+		data->lut_size = 8;
+		break;
+	case lm96163:
+		data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
+		data->lut_size = 12;
+		data->trutherm
+		  = i2c_smbus_read_byte_data(client,
+					     LM96163_REG_TRUTHERM) & 0x02;
+		break;
+	}
+	convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
+	if (unlikely(convrate > LM63_MAX_CONVRATE))
+		convrate = LM63_MAX_CONVRATE;
+	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
+						convrate);
+
+	/*
+	 * For LM96163, check if high resolution PWM
+	 * and unsigned temperature format is enabled.
+	 */
+	if (data->kind == lm96163) {
+		u8 config_enhanced
+		  = i2c_smbus_read_byte_data(client,
+					     LM96163_REG_CONFIG_ENHANCED);
+		if (config_enhanced & 0x20)
+			data->lut_temp_highres = true;
+		if ((config_enhanced & 0x10)
+		    && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
+			data->pwm_highres = true;
+		if (config_enhanced & 0x08)
+			data->remote_unsigned = true;
+	}
+
+	/* Show some debug info about the LM63 configuration */
+	if (data->kind == lm63)
+		dev_dbg(dev, "Alert/tach pin configured for %s\n",
+			(data->config & 0x04) ? "tachometer input" :
+			"alert output");
+	dev_dbg(dev, "PWM clock %s kHz, output frequency %u Hz\n",
+		(data->config_fan & 0x08) ? "1.4" : "360",
+		((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
+	dev_dbg(dev, "PWM output active %s, %s mode\n",
+		(data->config_fan & 0x10) ? "low" : "high",
+		(data->config_fan & 0x20) ? "manual" : "auto");
+}
+
+static int lm63_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm63_data *data;
+	int groups = 0;
+
+	data = devm_kzalloc(dev, sizeof(struct lm63_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Set the device type */
+	data->kind = id->driver_data;
+	if (data->kind == lm64)
+		data->temp2_offset = 16000;
+
+	/* Initialize chip */
+	lm63_init_client(data);
+
+	/* Register sysfs hooks */
+	data->groups[groups++] = &lm63_group;
+	if (data->config & 0x04)	/* tachometer enabled */
+		data->groups[groups++] = &lm63_group_fan1;
+
+	if (data->kind == lm96163) {
+		data->groups[groups++] = &lm63_group_temp2_type;
+		data->groups[groups++] = &lm63_group_extra_lut;
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id lm63_id[] = {
+	{ "lm63", lm63 },
+	{ "lm64", lm64 },
+	{ "lm96163", lm96163 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm63_id);
+
+static struct i2c_driver lm63_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm63",
+	},
+	.probe		= lm63_probe,
+	.id_table	= lm63_id,
+	.detect		= lm63_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm63_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("LM63 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
new file mode 100644
index 0000000..583f883
--- /dev/null
+++ b/drivers/hwmon/lm70.c
@@ -0,0 +1,212 @@
+/*
+ * lm70.c
+ *
+ * The LM70 is a temperature sensor chip from National Semiconductor (NS).
+ * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
+ *
+ * The LM70 communicates with a host processor via an SPI/Microwire Bus
+ * interface. The complete datasheet is available at National's website
+ * here:
+ * http://www.national.com/pf/LM/LM70.html
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/mutex.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+
+
+#define DRVNAME		"lm70"
+
+#define LM70_CHIP_LM70		0	/* original NS LM70 */
+#define LM70_CHIP_TMP121	1	/* TI TMP121/TMP123 */
+#define LM70_CHIP_LM71		2	/* NS LM71 */
+#define LM70_CHIP_LM74		3	/* NS LM74 */
+
+struct lm70 {
+	struct spi_device *spi;
+	struct mutex lock;
+	unsigned int chip;
+};
+
+/* sysfs hook function */
+static ssize_t lm70_sense_temp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct lm70 *p_lm70 = dev_get_drvdata(dev);
+	struct spi_device *spi = p_lm70->spi;
+	int status, val = 0;
+	u8 rxbuf[2];
+	s16 raw = 0;
+
+	if (mutex_lock_interruptible(&p_lm70->lock))
+		return -ERESTARTSYS;
+
+	/*
+	 * spi_read() requires a DMA-safe buffer; so we use
+	 * spi_write_then_read(), transmitting 0 bytes.
+	 */
+	status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
+	if (status < 0) {
+		pr_warn("spi_write_then_read failed with status %d\n", status);
+		goto out;
+	}
+	raw = (rxbuf[0] << 8) + rxbuf[1];
+	dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n",
+		rxbuf[0], rxbuf[1], raw);
+
+	/*
+	 * LM70:
+	 * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
+	 * complement value. Only the MSB 11 bits (1 sign + 10 temperature
+	 * bits) are meaningful; the LSB 5 bits are to be discarded.
+	 * See the datasheet.
+	 *
+	 * Further, each bit represents 0.25 degrees Celsius; so, multiply
+	 * by 0.25. Also multiply by 1000 to represent in millidegrees
+	 * Celsius.
+	 * So it's equivalent to multiplying by 0.25 * 1000 = 250.
+	 *
+	 * LM74 and TMP121/TMP123:
+	 * 13 bits of 2's complement data, discard LSB 3 bits,
+	 * resolution 0.0625 degrees celsius.
+	 *
+	 * LM71:
+	 * 14 bits of 2's complement data, discard LSB 2 bits,
+	 * resolution 0.0312 degrees celsius.
+	 */
+	switch (p_lm70->chip) {
+	case LM70_CHIP_LM70:
+		val = ((int)raw / 32) * 250;
+		break;
+
+	case LM70_CHIP_TMP121:
+	case LM70_CHIP_LM74:
+		val = ((int)raw / 8) * 625 / 10;
+		break;
+
+	case LM70_CHIP_LM71:
+		val = ((int)raw / 4) * 3125 / 100;
+		break;
+	}
+
+	status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
+out:
+	mutex_unlock(&p_lm70->lock);
+	return status;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
+
+static struct attribute *lm70_attrs[] = {
+	&dev_attr_temp1_input.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(lm70);
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm70_of_ids[] = {
+	{
+		.compatible = "ti,lm70",
+		.data = (void *) LM70_CHIP_LM70,
+	},
+	{
+		.compatible = "ti,tmp121",
+		.data = (void *) LM70_CHIP_TMP121,
+	},
+	{
+		.compatible = "ti,lm71",
+		.data = (void *) LM70_CHIP_LM71,
+	},
+	{
+		.compatible = "ti,lm74",
+		.data = (void *) LM70_CHIP_LM74,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, lm70_of_ids);
+#endif
+
+static int lm70_probe(struct spi_device *spi)
+{
+	const struct of_device_id *match;
+	struct device *hwmon_dev;
+	struct lm70 *p_lm70;
+	int chip;
+
+	match = of_match_device(lm70_of_ids, &spi->dev);
+	if (match)
+		chip = (int)(uintptr_t)match->data;
+	else
+		chip = spi_get_device_id(spi)->driver_data;
+
+	/* signaling is SPI_MODE_0 */
+	if (spi->mode & (SPI_CPOL | SPI_CPHA))
+		return -EINVAL;
+
+	/* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
+
+	p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL);
+	if (!p_lm70)
+		return -ENOMEM;
+
+	mutex_init(&p_lm70->lock);
+	p_lm70->chip = chip;
+	p_lm70->spi = spi;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev,
+							   spi->modalias,
+							   p_lm70, lm70_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct spi_device_id lm70_ids[] = {
+	{ "lm70",   LM70_CHIP_LM70 },
+	{ "tmp121", LM70_CHIP_TMP121 },
+	{ "lm71",   LM70_CHIP_LM71 },
+	{ "lm74",   LM70_CHIP_LM74 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, lm70_ids);
+
+static struct spi_driver lm70_driver = {
+	.driver = {
+		.name	= "lm70",
+		.of_match_table	= of_match_ptr(lm70_of_ids),
+	},
+	.id_table = lm70_ids,
+	.probe	= lm70_probe,
+};
+
+module_spi_driver(lm70_driver);
+
+MODULE_AUTHOR("Kaiwan N Billimoria");
+MODULE_DESCRIPTION("NS LM70 and compatibles Linux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
new file mode 100644
index 0000000..9653bb8
--- /dev/null
+++ b/drivers/hwmon/lm73.c
@@ -0,0 +1,287 @@
+/*
+ * LM73 Sensor driver
+ * Based on LM75
+ *
+ * Copyright (C) 2007, CenoSYS (www.cenosys.com).
+ * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu).
+ *
+ * Guillaume Ligneul <guillaume.ligneul@gmail.com>
+ * Adrien Demarez <adrien.demarez@bolloretelecom.eu>
+ * Jeremy Laine <jeremy.laine@bolloretelecom.eu>
+ * Chris Verges <kg4ysn@gmail.com>
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
+					0x4d, 0x4e, I2C_CLIENT_END };
+
+/* LM73 registers */
+#define LM73_REG_INPUT		0x00
+#define LM73_REG_CONF		0x01
+#define LM73_REG_MAX		0x02
+#define LM73_REG_MIN		0x03
+#define LM73_REG_CTRL		0x04
+#define LM73_REG_ID		0x07
+
+#define LM73_ID			0x9001	/* 0x0190, byte-swapped */
+#define DRVNAME			"lm73"
+#define LM73_TEMP_MIN		(-256000 / 250)
+#define LM73_TEMP_MAX		(255750 / 250)
+
+#define LM73_CTRL_RES_SHIFT	5
+#define LM73_CTRL_RES_MASK	(BIT(5) | BIT(6))
+#define LM73_CTRL_TO_MASK	BIT(7)
+
+#define LM73_CTRL_HI_SHIFT	2
+#define LM73_CTRL_LO_SHIFT	1
+
+static const unsigned short lm73_convrates[] = {
+	14,	/* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
+	28,	/* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
+	56,	/* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
+	112,	/* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
+};
+
+struct lm73_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	u8 ctrl;			/* control register value */
+};
+
+/*-----------------------------------------------------------------------*/
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm73_data *data = dev_get_drvdata(dev);
+	long temp;
+	short value;
+	s32 err;
+
+	int status = kstrtol(buf, 10, &temp);
+	if (status < 0)
+		return status;
+
+	/* Write value */
+	value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5;
+	err = i2c_smbus_write_word_swapped(data->client, attr->index, value);
+	return (err < 0) ? err : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm73_data *data = dev_get_drvdata(dev);
+	int temp;
+
+	s32 err = i2c_smbus_read_word_swapped(data->client, attr->index);
+	if (err < 0)
+		return err;
+
+	/* use integer division instead of equivalent right shift to
+	   guarantee arithmetic shift and preserve the sign */
+	temp = (((s16) err) * 250) / 32;
+	return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	struct lm73_data *data = dev_get_drvdata(dev);
+	unsigned long convrate;
+	s32 err;
+	int res = 0;
+
+	err = kstrtoul(buf, 10, &convrate);
+	if (err < 0)
+		return err;
+
+	/*
+	 * Convert the desired conversion rate into register bits.
+	 * res is already initialized, and everything past the second-to-last
+	 * value in the array is treated as belonging to the last value
+	 * in the array.
+	 */
+	while (res < (ARRAY_SIZE(lm73_convrates) - 1) &&
+			convrate > lm73_convrates[res])
+		res++;
+
+	mutex_lock(&data->lock);
+	data->ctrl &= LM73_CTRL_TO_MASK;
+	data->ctrl |= res << LM73_CTRL_RES_SHIFT;
+	err = i2c_smbus_write_byte_data(data->client, LM73_REG_CTRL,
+					data->ctrl);
+	mutex_unlock(&data->lock);
+
+	if (err < 0)
+		return err;
+
+	return count;
+}
+
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+			     char *buf)
+{
+	struct lm73_data *data = dev_get_drvdata(dev);
+	int res;
+
+	res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
+	return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
+}
+
+static ssize_t show_maxmin_alarm(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm73_data *data = dev_get_drvdata(dev);
+	s32 ctrl;
+
+	mutex_lock(&data->lock);
+	ctrl = i2c_smbus_read_byte_data(data->client, LM73_REG_CTRL);
+	if (ctrl < 0)
+		goto abort;
+	data->ctrl = ctrl;
+	mutex_unlock(&data->lock);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1);
+
+abort:
+	mutex_unlock(&data->lock);
+	return ctrl;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, LM73_REG_MAX);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, LM73_REG_MIN);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+			show_temp, NULL, LM73_REG_INPUT);
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+			show_convrate, set_convrate, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+			show_maxmin_alarm, NULL, LM73_CTRL_HI_SHIFT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+			show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT);
+
+static struct attribute *lm73_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_update_interval.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm73);
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int
+lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm73_data *data;
+	int ctrl;
+
+	data = devm_kzalloc(dev, sizeof(struct lm73_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->lock);
+
+	ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+	if (ctrl < 0)
+		return ctrl;
+	data->ctrl = ctrl;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, lm73_groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(dev, "sensor '%s'\n", client->name);
+
+	return 0;
+}
+
+static const struct i2c_device_id lm73_ids[] = {
+	{ "lm73", 0 },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, lm73_ids);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm73_detect(struct i2c_client *new_client,
+			struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	int id, ctrl, conf;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	/*
+	 * Do as much detection as possible with byte reads first, as word
+	 * reads can confuse other devices.
+	 */
+	ctrl = i2c_smbus_read_byte_data(new_client, LM73_REG_CTRL);
+	if (ctrl < 0 || (ctrl & 0x10))
+		return -ENODEV;
+
+	conf = i2c_smbus_read_byte_data(new_client, LM73_REG_CONF);
+	if (conf < 0 || (conf & 0x0c))
+		return -ENODEV;
+
+	id = i2c_smbus_read_byte_data(new_client, LM73_REG_ID);
+	if (id < 0 || id != (LM73_ID & 0xff))
+		return -ENODEV;
+
+	/* Check device ID */
+	id = i2c_smbus_read_word_data(new_client, LM73_REG_ID);
+	if (id < 0 || id != LM73_ID)
+		return -ENODEV;
+
+	strlcpy(info->type, "lm73", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static struct i2c_driver lm73_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm73",
+	},
+	.probe		= lm73_probe,
+	.id_table	= lm73_ids,
+	.detect		= lm73_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm73_driver);
+
+MODULE_AUTHOR("Guillaume Ligneul <guillaume.ligneul@gmail.com>");
+MODULE_DESCRIPTION("LM73 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
new file mode 100644
index 0000000..0addc84
--- /dev/null
+++ b/drivers/hwmon/lm75.c
@@ -0,0 +1,567 @@
+/*
+ * lm75.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *
+ * 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/of.h>
+#include <linux/thermal.h>
+#include "lm75.h"
+
+
+/*
+ * This driver handles the LM75 and compatible digital temperature sensors.
+ */
+
+enum lm75_type {		/* keep sorted in alphabetical order */
+	adt75,
+	ds1775,
+	ds75,
+	ds7505,
+	g751,
+	lm75,
+	lm75a,
+	lm75b,
+	max6625,
+	max6626,
+	mcp980x,
+	stds75,
+	tcn75,
+	tmp100,
+	tmp101,
+	tmp105,
+	tmp112,
+	tmp175,
+	tmp275,
+	tmp75,
+	tmp75c,
+};
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+
+
+/* The LM75 registers */
+#define LM75_REG_CONF		0x01
+static const u8 LM75_REG_TEMP[3] = {
+	0x00,		/* input */
+	0x03,		/* max */
+	0x02,		/* hyst */
+};
+
+/* Each client has this additional data */
+struct lm75_data {
+	struct i2c_client	*client;
+	struct device		*hwmon_dev;
+	struct thermal_zone_device	*tz;
+	struct mutex		update_lock;
+	u8			orig_conf;
+	u8			resolution;	/* In bits, between 9 and 12 */
+	u8			resolution_limits;
+	char			valid;		/* !=0 if registers are valid */
+	unsigned long		last_updated;	/* In jiffies */
+	unsigned long		sample_time;	/* In jiffies */
+	s16			temp[3];	/* Register values,
+						   0 = input
+						   1 = max
+						   2 = hyst */
+};
+
+static int lm75_read_value(struct i2c_client *client, u8 reg);
+static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
+static struct lm75_data *lm75_update_device(struct device *dev);
+
+
+/*-----------------------------------------------------------------------*/
+
+static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
+{
+	return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
+}
+
+/* sysfs attributes for hwmon */
+
+static int lm75_read_temp(void *dev, int *temp)
+{
+	struct lm75_data *data = lm75_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	*temp = lm75_reg_to_mc(data->temp[0], data->resolution);
+
+	return 0;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm75_data *data = lm75_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%ld\n", lm75_reg_to_mc(data->temp[attr->index],
+						    data->resolution));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm75_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long temp;
+	int error;
+	u8 resolution;
+
+	error = kstrtol(buf, 10, &temp);
+	if (error)
+		return error;
+
+	/*
+	 * Resolution of limit registers is assumed to be the same as the
+	 * temperature input register resolution unless given explicitly.
+	 */
+	if (attr->index && data->resolution_limits)
+		resolution = data->resolution_limits;
+	else
+		resolution = data->resolution;
+
+	mutex_lock(&data->update_lock);
+	temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
+	data->temp[nr] = DIV_ROUND_CLOSEST(temp  << (resolution - 8),
+					   1000) << (16 - resolution);
+	lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+
+static struct attribute *lm75_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+
+	NULL
+};
+ATTRIBUTE_GROUPS(lm75);
+
+static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = {
+	.get_temp = lm75_read_temp,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int
+lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct lm75_data *data;
+	int status;
+	u8 set_mask, clr_mask;
+	int new;
+	enum lm75_type kind = id->driver_data;
+
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -EIO;
+
+	data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
+	 * Then tweak to be more precise when appropriate.
+	 */
+	set_mask = 0;
+	clr_mask = LM75_SHUTDOWN;		/* continuous conversions */
+
+	switch (kind) {
+	case adt75:
+		clr_mask |= 1 << 5;		/* not one-shot mode */
+		data->resolution = 12;
+		data->sample_time = HZ / 8;
+		break;
+	case ds1775:
+	case ds75:
+	case stds75:
+		clr_mask |= 3 << 5;
+		set_mask |= 2 << 5;		/* 11-bit mode */
+		data->resolution = 11;
+		data->sample_time = HZ;
+		break;
+	case ds7505:
+		set_mask |= 3 << 5;		/* 12-bit mode */
+		data->resolution = 12;
+		data->sample_time = HZ / 4;
+		break;
+	case g751:
+	case lm75:
+	case lm75a:
+		data->resolution = 9;
+		data->sample_time = HZ / 2;
+		break;
+	case lm75b:
+		data->resolution = 11;
+		data->sample_time = HZ / 4;
+		break;
+	case max6625:
+		data->resolution = 9;
+		data->sample_time = HZ / 4;
+		break;
+	case max6626:
+		data->resolution = 12;
+		data->resolution_limits = 9;
+		data->sample_time = HZ / 4;
+		break;
+	case tcn75:
+		data->resolution = 9;
+		data->sample_time = HZ / 8;
+		break;
+	case mcp980x:
+		data->resolution_limits = 9;
+		/* fall through */
+	case tmp100:
+	case tmp101:
+		set_mask |= 3 << 5;		/* 12-bit mode */
+		data->resolution = 12;
+		data->sample_time = HZ;
+		clr_mask |= 1 << 7;		/* not one-shot mode */
+		break;
+	case tmp112:
+		set_mask |= 3 << 5;		/* 12-bit mode */
+		clr_mask |= 1 << 7;		/* not one-shot mode */
+		data->resolution = 12;
+		data->sample_time = HZ / 4;
+		break;
+	case tmp105:
+	case tmp175:
+	case tmp275:
+	case tmp75:
+		set_mask |= 3 << 5;		/* 12-bit mode */
+		clr_mask |= 1 << 7;		/* not one-shot mode */
+		data->resolution = 12;
+		data->sample_time = HZ / 2;
+		break;
+	case tmp75c:
+		clr_mask |= 1 << 5;		/* not one-shot mode */
+		data->resolution = 12;
+		data->sample_time = HZ / 4;
+		break;
+	}
+
+	/* configure as specified */
+	status = lm75_read_value(client, LM75_REG_CONF);
+	if (status < 0) {
+		dev_dbg(dev, "Can't read config? %d\n", status);
+		return status;
+	}
+	data->orig_conf = status;
+	new = status & ~clr_mask;
+	new |= set_mask;
+	if (status != new)
+		lm75_write_value(client, LM75_REG_CONF, new);
+	dev_dbg(dev, "Config %02x\n", new);
+
+	data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+							    data, lm75_groups);
+	if (IS_ERR(data->hwmon_dev))
+		return PTR_ERR(data->hwmon_dev);
+
+	data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0,
+						   data->hwmon_dev,
+						   &lm75_of_thermal_ops);
+	if (IS_ERR(data->tz))
+		data->tz = NULL;
+
+	dev_info(dev, "%s: sensor '%s'\n",
+		 dev_name(data->hwmon_dev), client->name);
+
+	return 0;
+}
+
+static int lm75_remove(struct i2c_client *client)
+{
+	struct lm75_data *data = i2c_get_clientdata(client);
+
+	thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz);
+	hwmon_device_unregister(data->hwmon_dev);
+	lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
+	return 0;
+}
+
+static const struct i2c_device_id lm75_ids[] = {
+	{ "adt75", adt75, },
+	{ "ds1775", ds1775, },
+	{ "ds75", ds75, },
+	{ "ds7505", ds7505, },
+	{ "g751", g751, },
+	{ "lm75", lm75, },
+	{ "lm75a", lm75a, },
+	{ "lm75b", lm75b, },
+	{ "max6625", max6625, },
+	{ "max6626", max6626, },
+	{ "mcp980x", mcp980x, },
+	{ "stds75", stds75, },
+	{ "tcn75", tcn75, },
+	{ "tmp100", tmp100, },
+	{ "tmp101", tmp101, },
+	{ "tmp105", tmp105, },
+	{ "tmp112", tmp112, },
+	{ "tmp175", tmp175, },
+	{ "tmp275", tmp275, },
+	{ "tmp75", tmp75, },
+	{ "tmp75c", tmp75c, },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, lm75_ids);
+
+#define LM75A_ID 0xA1
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm75_detect(struct i2c_client *new_client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	int i;
+	int conf, hyst, os;
+	bool is_lm75a = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	/*
+	 * Now, we do the remaining detection. There is no identification-
+	 * dedicated register so we have to rely on several tricks:
+	 * unused bits, registers cycling over 8-address boundaries,
+	 * addresses 0x04-0x07 returning the last read value.
+	 * The cycling+unused addresses combination is not tested,
+	 * since it would significantly slow the detection down and would
+	 * hardly add any value.
+	 *
+	 * The National Semiconductor LM75A is different than earlier
+	 * LM75s.  It has an ID byte of 0xaX (where X is the chip
+	 * revision, with 1 being the only revision in existence) in
+	 * register 7, and unused registers return 0xff rather than the
+	 * last read value.
+	 *
+	 * Note that this function only detects the original National
+	 * Semiconductor LM75 and the LM75A. Clones from other vendors
+	 * aren't detected, on purpose, because they are typically never
+	 * found on PC hardware. They are found on embedded designs where
+	 * they can be instantiated explicitly so detection is not needed.
+	 * The absence of identification registers on all these clones
+	 * would make their exhaustive detection very difficult and weak,
+	 * and odds are that the driver would bind to unsupported devices.
+	 */
+
+	/* Unused bits */
+	conf = i2c_smbus_read_byte_data(new_client, 1);
+	if (conf & 0xe0)
+		return -ENODEV;
+
+	/* First check for LM75A */
+	if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) {
+		/* LM75A returns 0xff on unused registers so
+		   just to be sure we check for that too. */
+		if (i2c_smbus_read_byte_data(new_client, 4) != 0xff
+		 || i2c_smbus_read_byte_data(new_client, 5) != 0xff
+		 || i2c_smbus_read_byte_data(new_client, 6) != 0xff)
+			return -ENODEV;
+		is_lm75a = 1;
+		hyst = i2c_smbus_read_byte_data(new_client, 2);
+		os = i2c_smbus_read_byte_data(new_client, 3);
+	} else { /* Traditional style LM75 detection */
+		/* Unused addresses */
+		hyst = i2c_smbus_read_byte_data(new_client, 2);
+		if (i2c_smbus_read_byte_data(new_client, 4) != hyst
+		 || i2c_smbus_read_byte_data(new_client, 5) != hyst
+		 || i2c_smbus_read_byte_data(new_client, 6) != hyst
+		 || i2c_smbus_read_byte_data(new_client, 7) != hyst)
+			return -ENODEV;
+		os = i2c_smbus_read_byte_data(new_client, 3);
+		if (i2c_smbus_read_byte_data(new_client, 4) != os
+		 || i2c_smbus_read_byte_data(new_client, 5) != os
+		 || i2c_smbus_read_byte_data(new_client, 6) != os
+		 || i2c_smbus_read_byte_data(new_client, 7) != os)
+			return -ENODEV;
+	}
+	/*
+	 * It is very unlikely that this is a LM75 if both
+	 * hysteresis and temperature limit registers are 0.
+	 */
+	if (hyst == 0 && os == 0)
+		return -ENODEV;
+
+	/* Addresses cycling */
+	for (i = 8; i <= 248; i += 40) {
+		if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
+		 || i2c_smbus_read_byte_data(new_client, i + 2) != hyst
+		 || i2c_smbus_read_byte_data(new_client, i + 3) != os)
+			return -ENODEV;
+		if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7)
+				!= LM75A_ID)
+			return -ENODEV;
+	}
+
+	strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lm75_suspend(struct device *dev)
+{
+	int status;
+	struct i2c_client *client = to_i2c_client(dev);
+	status = lm75_read_value(client, LM75_REG_CONF);
+	if (status < 0) {
+		dev_dbg(&client->dev, "Can't read config? %d\n", status);
+		return status;
+	}
+	status = status | LM75_SHUTDOWN;
+	lm75_write_value(client, LM75_REG_CONF, status);
+	return 0;
+}
+
+static int lm75_resume(struct device *dev)
+{
+	int status;
+	struct i2c_client *client = to_i2c_client(dev);
+	status = lm75_read_value(client, LM75_REG_CONF);
+	if (status < 0) {
+		dev_dbg(&client->dev, "Can't read config? %d\n", status);
+		return status;
+	}
+	status = status & ~LM75_SHUTDOWN;
+	lm75_write_value(client, LM75_REG_CONF, status);
+	return 0;
+}
+
+static const struct dev_pm_ops lm75_dev_pm_ops = {
+	.suspend	= lm75_suspend,
+	.resume		= lm75_resume,
+};
+#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops)
+#else
+#define LM75_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver lm75_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm75",
+		.pm	= LM75_DEV_PM_OPS,
+	},
+	.probe		= lm75_probe,
+	.remove		= lm75_remove,
+	.id_table	= lm75_ids,
+	.detect		= lm75_detect,
+	.address_list	= normal_i2c,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* register access */
+
+/*
+ * All registers are word-sized, except for the configuration register.
+ * LM75 uses a high-byte first convention, which is exactly opposite to
+ * the SMBus standard.
+ */
+static int lm75_read_value(struct i2c_client *client, u8 reg)
+{
+	if (reg == LM75_REG_CONF)
+		return i2c_smbus_read_byte_data(client, reg);
+	else
+		return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if (reg == LM75_REG_CONF)
+		return i2c_smbus_write_byte_data(client, reg, value);
+	else
+		return i2c_smbus_write_word_swapped(client, reg, value);
+}
+
+static struct lm75_data *lm75_update_device(struct device *dev)
+{
+	struct lm75_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct lm75_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + data->sample_time)
+	    || !data->valid) {
+		int i;
+		dev_dbg(&client->dev, "Starting lm75 update\n");
+
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			int status;
+
+			status = lm75_read_value(client, LM75_REG_TEMP[i]);
+			if (unlikely(status < 0)) {
+				dev_dbg(dev,
+					"LM75: Failed to read value: reg %d, error %d\n",
+					LM75_REG_TEMP[i], status);
+				ret = ERR_PTR(status);
+				data->valid = 0;
+				goto abort;
+			}
+			data->temp[i] = status;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+module_i2c_driver(lm75_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("LM75 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
new file mode 100644
index 0000000..5cde94e
--- /dev/null
+++ b/drivers/hwmon/lm75.h
@@ -0,0 +1,49 @@
+/*
+    lm75.h - Part of lm_sensors, Linux kernel modules for hardware
+	      monitoring
+    Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    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.
+*/
+
+/*
+    This file contains common code for encoding/decoding LM75 type
+    temperature readings, which are emulated by many of the chips
+    we support.  As the user is unlikely to load more than one driver
+    which contains this code, we don't worry about the wasted space.
+*/
+
+#include <linux/kernel.h>
+
+/* straight from the datasheet */
+#define LM75_TEMP_MIN (-55000)
+#define LM75_TEMP_MAX 125000
+#define LM75_SHUTDOWN 0x01
+
+/* TEMP: 0.001C/bit (-55C to +125C)
+   REG: (0.5C/bit, two's complement) << 7 */
+static inline u16 LM75_TEMP_TO_REG(long temp)
+{
+	int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
+	ntemp += (ntemp < 0 ? -250 : 250);
+	return (u16)((ntemp / 500) << 7);
+}
+
+static inline int LM75_TEMP_FROM_REG(u16 reg)
+{
+	/* use integer division instead of equivalent right shift to
+	   guarantee arithmetic shift and preserve the sign */
+	return ((s16)reg / 128) * 500;
+}
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
new file mode 100644
index 0000000..69b05cc
--- /dev/null
+++ b/drivers/hwmon/lm77.c
@@ -0,0 +1,373 @@
+/*
+ * lm77.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	    monitoring
+ *
+ * Copyright (c) 2004  Andras BALI <drewie@freemail.hu>
+ *
+ * Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>.  The LM77
+ * is a temperature sensor and thermal window comparator with 0.5 deg
+ * resolution made by National Semiconductor.  Complete datasheet can be
+ * obtained at their site:
+ *	http://www.national.com/pf/LM/LM77.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+						I2C_CLIENT_END };
+
+/* The LM77 registers */
+#define LM77_REG_TEMP		0x00
+#define LM77_REG_CONF		0x01
+#define LM77_REG_TEMP_HYST	0x02
+#define LM77_REG_TEMP_CRIT	0x03
+#define LM77_REG_TEMP_MIN	0x04
+#define LM77_REG_TEMP_MAX	0x05
+
+enum temp_index {
+	t_input = 0,
+	t_crit,
+	t_min,
+	t_max,
+	t_hyst,
+	t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+	[t_input] = LM77_REG_TEMP,
+	[t_min] = LM77_REG_TEMP_MIN,
+	[t_max] = LM77_REG_TEMP_MAX,
+	[t_crit] = LM77_REG_TEMP_CRIT,
+	[t_hyst] = LM77_REG_TEMP_HYST,
+};
+
+/* Each client has this additional data */
+struct lm77_data {
+	struct i2c_client	*client;
+	struct mutex		update_lock;
+	char			valid;
+	unsigned long		last_updated;	/* In jiffies */
+	int			temp[t_num_temp]; /* index using temp_index */
+	u8			alarms;
+};
+
+/* straight from the datasheet */
+#define LM77_TEMP_MIN (-55000)
+#define LM77_TEMP_MAX 125000
+
+/*
+ * In the temperature registers, the low 3 bits are not part of the
+ * temperature values; they are the status bits.
+ */
+static inline s16 LM77_TEMP_TO_REG(int temp)
+{
+	return (temp / 500) * 8;
+}
+
+static inline int LM77_TEMP_FROM_REG(s16 reg)
+{
+	return (reg / 8) * 500;
+}
+
+/*
+ * All registers are word-sized, except for the configuration register.
+ * The LM77 uses the high-byte first convention.
+ */
+static u16 lm77_read_value(struct i2c_client *client, u8 reg)
+{
+	if (reg == LM77_REG_CONF)
+		return i2c_smbus_read_byte_data(client, reg);
+	else
+		return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if (reg == LM77_REG_CONF)
+		return i2c_smbus_write_byte_data(client, reg, value);
+	else
+		return i2c_smbus_write_word_swapped(client, reg, value);
+}
+
+static struct lm77_data *lm77_update_device(struct device *dev)
+{
+	struct lm77_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		dev_dbg(&client->dev, "Starting lm77 update\n");
+		for (i = 0; i < t_num_temp; i++) {
+			data->temp[i] =
+			  LM77_TEMP_FROM_REG(lm77_read_value(client,
+							     temp_regs[i]));
+		}
+		data->alarms =
+			lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* sysfs stuff */
+
+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 lm77_data *data = lm77_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->temp[attr->index]);
+}
+
+static ssize_t show_temp_hyst(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm77_data *data = lm77_update_device(dev);
+	int nr = attr->index;
+	int temp;
+
+	temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
+			     data->temp[nr] - data->temp[t_hyst];
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm77_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, LM77_TEMP_MIN, LM77_TEMP_MAX);
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = val;
+	lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * hysteresis is stored as a relative value on the chip, so it has to be
+ * converted first.
+ */
+static ssize_t set_temp_hyst(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct lm77_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	val = clamp_val(data->temp[t_crit] - val, LM77_TEMP_MIN, LM77_TEMP_MAX);
+	data->temp[t_hyst] = val;
+	lm77_write_value(client, LM77_REG_TEMP_HYST,
+			 LM77_TEMP_TO_REG(data->temp[t_hyst]));
+	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 lm77_data *data = lm77_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+			  set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
+
+static struct attribute *lm77_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm77);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int i, cur, conf, hyst, crit, min, max;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	/*
+	 * Here comes the remaining detection.  Since the LM77 has no
+	 * register dedicated to identification, we have to rely on the
+	 * following tricks:
+	 *
+	 * 1. the high 4 bits represent the sign and thus they should
+	 *    always be the same
+	 * 2. the high 3 bits are unused in the configuration register
+	 * 3. addresses 0x06 and 0x07 return the last read value
+	 * 4. registers cycling over 8-address boundaries
+	 *
+	 * Word-sized registers are high-byte first.
+	 */
+
+	/* addresses cycling */
+	cur = i2c_smbus_read_word_data(client, 0);
+	conf = i2c_smbus_read_byte_data(client, 1);
+	hyst = i2c_smbus_read_word_data(client, 2);
+	crit = i2c_smbus_read_word_data(client, 3);
+	min = i2c_smbus_read_word_data(client, 4);
+	max = i2c_smbus_read_word_data(client, 5);
+	for (i = 8; i <= 0xff; i += 8) {
+		if (i2c_smbus_read_byte_data(client, i + 1) != conf
+		 || i2c_smbus_read_word_data(client, i + 2) != hyst
+		 || i2c_smbus_read_word_data(client, i + 3) != crit
+		 || i2c_smbus_read_word_data(client, i + 4) != min
+		 || i2c_smbus_read_word_data(client, i + 5) != max)
+			return -ENODEV;
+	}
+
+	/* sign bits */
+	if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
+	 || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0)
+	 || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
+	 || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
+	 || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
+		return -ENODEV;
+
+	/* unused bits */
+	if (conf & 0xe0)
+		return -ENODEV;
+
+	/* 0x06 and 0x07 return the last read value */
+	cur = i2c_smbus_read_word_data(client, 0);
+	if (i2c_smbus_read_word_data(client, 6) != cur
+	 || i2c_smbus_read_word_data(client, 7) != cur)
+		return -ENODEV;
+	hyst = i2c_smbus_read_word_data(client, 2);
+	if (i2c_smbus_read_word_data(client, 6) != hyst
+	 || i2c_smbus_read_word_data(client, 7) != hyst)
+		return -ENODEV;
+	min = i2c_smbus_read_word_data(client, 4);
+	if (i2c_smbus_read_word_data(client, 6) != min
+	 || i2c_smbus_read_word_data(client, 7) != min)
+		return -ENODEV;
+
+	strlcpy(info->type, "lm77", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void lm77_init_client(struct i2c_client *client)
+{
+	/* Initialize the LM77 chip - turn off shutdown mode */
+	int conf = lm77_read_value(client, LM77_REG_CONF);
+	if (conf & 1)
+		lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
+}
+
+static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm77_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM77 chip */
+	lm77_init_client(client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, lm77_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id lm77_id[] = {
+	{ "lm77", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm77_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver lm77_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm77",
+	},
+	.probe		= lm77_probe,
+	.id_table	= lm77_id,
+	.detect		= lm77_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm77_driver);
+
+MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>");
+MODULE_DESCRIPTION("LM77 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
new file mode 100644
index 0000000..539efe4
--- /dev/null
+++ b/drivers/hwmon/lm78.c
@@ -0,0 +1,1047 @@
+/*
+ * lm78.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	    monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ * Copyright (c) 2007, 2011  Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+#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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_ISA
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+						0x2e, 0x2f, I2C_CLIENT_END };
+enum chips { lm78, lm79 };
+
+/* Many LM78 constants specified below */
+
+/* Length of ISA address segment */
+#define LM78_EXTENT 8
+
+/* Where are the ISA address/data registers relative to the base address */
+#define LM78_ADDR_REG_OFFSET 5
+#define LM78_DATA_REG_OFFSET 6
+
+/* The LM78 registers */
+#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2)
+#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2)
+#define LM78_REG_IN(nr) (0x20 + (nr))
+
+#define LM78_REG_FAN_MIN(nr) (0x3b + (nr))
+#define LM78_REG_FAN(nr) (0x28 + (nr))
+
+#define LM78_REG_TEMP 0x27
+#define LM78_REG_TEMP_OVER 0x39
+#define LM78_REG_TEMP_HYST 0x3a
+
+#define LM78_REG_ALARM1 0x41
+#define LM78_REG_ALARM2 0x42
+
+#define LM78_REG_VID_FANDIV 0x47
+
+#define LM78_REG_CONFIG 0x40
+#define LM78_REG_CHIPID 0x49
+#define LM78_REG_I2C_ADDR 0x48
+
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants.
+ */
+
+/*
+ * IN: mV (0V to 4.08V)
+ * REG: 16mV/bit
+ */
+static inline u8 IN_TO_REG(unsigned long val)
+{
+	unsigned long nval = clamp_val(val, 0, 4080);
+	return (nval + 8) / 16;
+}
+#define IN_FROM_REG(val) ((val) *  16)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm <= 0)
+		return 255;
+	if (rpm > 1350000)
+		return 1;
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static inline int FAN_FROM_REG(u8 val, int div)
+{
+	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
+}
+
+/*
+ * TEMP: mC (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static inline s8 TEMP_TO_REG(long val)
+{
+	int nval = clamp_val(val, -128000, 127000) ;
+	return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000;
+}
+
+static inline int TEMP_FROM_REG(s8 val)
+{
+	return val * 1000;
+}
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+struct lm78_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	enum chips type;
+
+	/* For ISA device only */
+	const char *name;
+	int isa_addr;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[7];		/* Register value */
+	u8 in_max[7];		/* Register value */
+	u8 in_min[7];		/* Register value */
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_over;		/* Register value */
+	s8 temp_hyst;		/* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 vid;			/* Register encoding, combined */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+
+static int lm78_read_value(struct lm78_data *data, u8 reg);
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value);
+static struct lm78_data *lm78_update_device(struct device *dev);
+static void lm78_init_device(struct lm78_data *data);
+
+
+/* 7 Voltages */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val);
+	lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val);
+	lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_in_offset(offset)					\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
+
+show_in_offset(0);
+show_in_offset(1);
+show_in_offset(2);
+show_in_offset(3);
+show_in_offset(4);
+show_in_offset(5);
+show_in_offset(6);
+
+/* Temperature */
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
+}
+
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+			      char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
+}
+
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+			     const char *buf, size_t count)
+{
+	struct lm78_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_over = TEMP_TO_REG(val);
+	lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+			      char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
+}
+
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+			     const char *buf, size_t count)
+{
+	struct lm78_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_hyst = TEMP_TO_REG(val);
+	lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		show_temp_over, set_temp_over);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		show_temp_hyst, set_temp_hyst);
+
+/* 3 Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long min;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	switch (val) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		dev_err(dev,
+			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+			val);
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	reg = lm78_read_value(data, LM78_REG_VID_FANDIV);
+	switch (nr) {
+	case 0:
+		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
+		break;
+	case 1:
+		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
+		break;
+	}
+	lm78_write_value(data, LM78_REG_VID_FANDIV, reg);
+
+	data->fan_min[nr] =
+		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define show_fan_offset(offset)				\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,		\
+		show_fan, NULL, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_fan_min, set_fan_min, offset - 1);
+
+show_fan_offset(1);
+show_fan_offset(2);
+show_fan_offset(3);
+
+/* Fan 3 divisor is locked in H/W */
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		show_fan_div, set_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2);
+
+/* VID */
+static ssize_t show_vid(struct device *dev, struct device_attribute *da,
+			char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct lm78_data *data = lm78_update_device(dev);
+	int nr = to_sensor_dev_attr(da)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+static struct attribute *lm78_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_max_hyst.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_cpu0_vid.attr,
+
+	NULL
+};
+
+ATTRIBUTE_GROUPS(lm78);
+
+/*
+ * ISA related code
+ */
+#ifdef CONFIG_ISA
+
+/* ISA device, if found */
+static struct platform_device *pdev;
+
+static unsigned short isa_address = 0x290;
+
+static struct lm78_data *lm78_data_if_isa(void)
+{
+	return pdev ? platform_get_drvdata(pdev) : NULL;
+}
+
+/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
+static int lm78_alias_detect(struct i2c_client *client, u8 chipid)
+{
+	struct lm78_data *isa;
+	int i;
+
+	if (!pdev)	/* No ISA chip */
+		return 0;
+	isa = platform_get_drvdata(pdev);
+
+	if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr)
+		return 0;	/* Address doesn't match */
+	if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe))
+		return 0;	/* Chip type doesn't match */
+
+	/*
+	 * We compare all the limit registers, the config register and the
+	 * interrupt mask registers
+	 */
+	for (i = 0x2b; i <= 0x3d; i++) {
+		if (lm78_read_value(isa, i) !=
+		    i2c_smbus_read_byte_data(client, i))
+			return 0;
+	}
+	if (lm78_read_value(isa, LM78_REG_CONFIG) !=
+	    i2c_smbus_read_byte_data(client, LM78_REG_CONFIG))
+		return 0;
+	for (i = 0x43; i <= 0x46; i++) {
+		if (lm78_read_value(isa, i) !=
+		    i2c_smbus_read_byte_data(client, i))
+			return 0;
+	}
+
+	return 1;
+}
+#else /* !CONFIG_ISA */
+
+static int lm78_alias_detect(struct i2c_client *client, u8 chipid)
+{
+	return 0;
+}
+
+static struct lm78_data *lm78_data_if_isa(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_ISA */
+
+static int lm78_i2c_detect(struct i2c_client *client,
+			   struct i2c_board_info *info)
+{
+	int i;
+	struct lm78_data *isa = lm78_data_if_isa();
+	const char *client_name;
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/*
+	 * We block updates of the ISA device to minimize the risk of
+	 * concurrent access to the same LM78 chip through different
+	 * interfaces.
+	 */
+	if (isa)
+		mutex_lock(&isa->update_lock);
+
+	if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80)
+	 || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR) != address)
+		goto err_nodev;
+
+	/* Explicitly prevent the misdetection of Winbond chips */
+	i = i2c_smbus_read_byte_data(client, 0x4f);
+	if (i == 0xa3 || i == 0x5c)
+		goto err_nodev;
+
+	/* Determine the chip type. */
+	i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID);
+	if (i == 0x00 || i == 0x20	/* LM78 */
+	 || i == 0x40)			/* LM78-J */
+		client_name = "lm78";
+	else if ((i & 0xfe) == 0xc0)
+		client_name = "lm79";
+	else
+		goto err_nodev;
+
+	if (lm78_alias_detect(client, i)) {
+		dev_dbg(&adapter->dev,
+			"Device at 0x%02x appears to be the same as ISA device\n",
+			address);
+		goto err_nodev;
+	}
+
+	if (isa)
+		mutex_unlock(&isa->update_lock);
+
+	strlcpy(info->type, client_name, I2C_NAME_SIZE);
+
+	return 0;
+
+ err_nodev:
+	if (isa)
+		mutex_unlock(&isa->update_lock);
+	return -ENODEV;
+}
+
+static int lm78_i2c_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm78_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->type = id->driver_data;
+
+	/* Initialize the LM78 chip */
+	lm78_init_device(data);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, lm78_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id lm78_i2c_id[] = {
+	{ "lm78", lm78 },
+	{ "lm79", lm79 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm78_i2c_id);
+
+static struct i2c_driver lm78_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm78",
+	},
+	.probe		= lm78_i2c_probe,
+	.id_table	= lm78_i2c_id,
+	.detect		= lm78_i2c_detect,
+	.address_list	= normal_i2c,
+};
+
+/*
+ * The SMBus locks itself, but ISA access must be locked explicitly!
+ * We don't want to lock the whole ISA bus, so we lock each client
+ * separately.
+ * We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the LM78 access and should not be necessary.
+ */
+static int lm78_read_value(struct lm78_data *data, u8 reg)
+{
+	struct i2c_client *client = data->client;
+
+#ifdef CONFIG_ISA
+	if (!client) { /* ISA device */
+		int res;
+		mutex_lock(&data->lock);
+		outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET);
+		res = inb_p(data->isa_addr + LM78_DATA_REG_OFFSET);
+		mutex_unlock(&data->lock);
+		return res;
+	} else
+#endif
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value)
+{
+	struct i2c_client *client = data->client;
+
+#ifdef CONFIG_ISA
+	if (!client) { /* ISA device */
+		mutex_lock(&data->lock);
+		outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET);
+		outb_p(value, data->isa_addr + LM78_DATA_REG_OFFSET);
+		mutex_unlock(&data->lock);
+		return 0;
+	} else
+#endif
+		return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static void lm78_init_device(struct lm78_data *data)
+{
+	u8 config;
+	int i;
+
+	/* Start monitoring */
+	config = lm78_read_value(data, LM78_REG_CONFIG);
+	if ((config & 0x09) != 0x01)
+		lm78_write_value(data, LM78_REG_CONFIG,
+				 (config & 0xf7) | 0x01);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 3; i++) {
+		data->fan_min[i] = lm78_read_value(data,
+					LM78_REG_FAN_MIN(i));
+	}
+
+	mutex_init(&data->update_lock);
+}
+
+static struct lm78_data *lm78_update_device(struct device *dev)
+{
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+
+		dev_dbg(dev, "Starting lm78 update\n");
+
+		for (i = 0; i <= 6; i++) {
+			data->in[i] =
+			    lm78_read_value(data, LM78_REG_IN(i));
+			data->in_min[i] =
+			    lm78_read_value(data, LM78_REG_IN_MIN(i));
+			data->in_max[i] =
+			    lm78_read_value(data, LM78_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 3; i++) {
+			data->fan[i] =
+			    lm78_read_value(data, LM78_REG_FAN(i));
+			data->fan_min[i] =
+			    lm78_read_value(data, LM78_REG_FAN_MIN(i));
+		}
+		data->temp = lm78_read_value(data, LM78_REG_TEMP);
+		data->temp_over =
+		    lm78_read_value(data, LM78_REG_TEMP_OVER);
+		data->temp_hyst =
+		    lm78_read_value(data, LM78_REG_TEMP_HYST);
+		i = lm78_read_value(data, LM78_REG_VID_FANDIV);
+		data->vid = i & 0x0f;
+		if (data->type == lm79)
+			data->vid |=
+			    (lm78_read_value(data, LM78_REG_CHIPID) &
+			     0x01) << 4;
+		else
+			data->vid |= 0x10;
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = i >> 6;
+		data->alarms = lm78_read_value(data, LM78_REG_ALARM1) +
+		    (lm78_read_value(data, LM78_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+
+		data->fan_div[2] = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+#ifdef CONFIG_ISA
+static int lm78_isa_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device *hwmon_dev;
+	struct lm78_data *data;
+	struct resource *res;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start + LM78_ADDR_REG_OFFSET,
+				 2, "lm78"))
+		return -EBUSY;
+
+	data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->lock);
+	data->isa_addr = res->start;
+	platform_set_drvdata(pdev, data);
+
+	if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) {
+		data->type = lm79;
+		data->name = "lm79";
+	} else {
+		data->type = lm78;
+		data->name = "lm78";
+	}
+
+	/* Initialize the LM78 chip */
+	lm78_init_device(data);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
+							   data, lm78_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver lm78_isa_driver = {
+	.driver = {
+		.name	= "lm78",
+	},
+	.probe		= lm78_isa_probe,
+};
+
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init lm78_isa_found(unsigned short address)
+{
+	int val, save, found = 0;
+	int port;
+
+	/*
+	 * Some boards declare base+0 to base+7 as a PNP device, some base+4
+	 * to base+7 and some base+5 to base+6. So we better request each port
+	 * individually for the probing phase.
+	 */
+	for (port = address; port < address + LM78_EXTENT; port++) {
+		if (!request_region(port, 1, "lm78")) {
+			pr_debug("Failed to request port 0x%x\n", port);
+			goto release;
+		}
+	}
+
+#define REALLY_SLOW_IO
+	/*
+	 * We need the timeouts for at least some LM78-like
+	 * chips. But only if we read 'undefined' registers.
+	 */
+	val = inb_p(address + 1);
+	if (inb_p(address + 2) != val
+	 || inb_p(address + 3) != val
+	 || inb_p(address + 7) != val)
+		goto release;
+#undef REALLY_SLOW_IO
+
+	/*
+	 * We should be able to change the 7 LSB of the address port. The
+	 * MSB (busy flag) should be clear initially, set after the write.
+	 */
+	save = inb_p(address + LM78_ADDR_REG_OFFSET);
+	if (save & 0x80)
+		goto release;
+	val = ~save & 0x7f;
+	outb_p(val, address + LM78_ADDR_REG_OFFSET);
+	if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) {
+		outb_p(save, address + LM78_ADDR_REG_OFFSET);
+		goto release;
+	}
+
+	/* We found a device, now see if it could be an LM78 */
+	outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val & 0x80)
+		goto release;
+	outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val < 0x03 || val > 0x77)	/* Not a valid I2C address */
+		goto release;
+
+	/* The busy flag should be clear again */
+	if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80)
+		goto release;
+
+	/* Explicitly prevent the misdetection of Winbond chips */
+	outb_p(0x4f, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0xa3 || val == 0x5c)
+		goto release;
+
+	/* Explicitly prevent the misdetection of ITE chips */
+	outb_p(0x58, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0x90)
+		goto release;
+
+	/* Determine the chip type */
+	outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0x00 || val == 0x20	/* LM78 */
+	 || val == 0x40			/* LM78-J */
+	 || (val & 0xfe) == 0xc0)	/* LM79 */
+		found = 1;
+
+	if (found)
+		pr_info("Found an %s chip at %#x\n",
+			val & 0x80 ? "LM79" : "LM78", (int)address);
+
+ release:
+	for (port--; port >= address; port--)
+		release_region(port, 1);
+	return found;
+}
+
+static int __init lm78_isa_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + LM78_EXTENT - 1,
+		.name	= "lm78",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("lm78", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+ exit_device_put:
+	platform_device_put(pdev);
+ exit:
+	pdev = NULL;
+	return err;
+}
+
+static int __init lm78_isa_register(void)
+{
+	int res;
+
+	if (lm78_isa_found(isa_address)) {
+		res = platform_driver_register(&lm78_isa_driver);
+		if (res)
+			goto exit;
+
+		/* Sets global pdev as a side effect */
+		res = lm78_isa_device_add(isa_address);
+		if (res)
+			goto exit_unreg_isa_driver;
+	}
+
+	return 0;
+
+ exit_unreg_isa_driver:
+	platform_driver_unregister(&lm78_isa_driver);
+ exit:
+	return res;
+}
+
+static void lm78_isa_unregister(void)
+{
+	if (pdev) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&lm78_isa_driver);
+	}
+}
+#else /* !CONFIG_ISA */
+
+static int __init lm78_isa_register(void)
+{
+	return 0;
+}
+
+static void lm78_isa_unregister(void)
+{
+}
+#endif /* CONFIG_ISA */
+
+static int __init sm_lm78_init(void)
+{
+	int res;
+
+	/*
+	 * We register the ISA device first, so that we can skip the
+	 * registration of an I2C interface to the same device.
+	 */
+	res = lm78_isa_register();
+	if (res)
+		goto exit;
+
+	res = i2c_add_driver(&lm78_driver);
+	if (res)
+		goto exit_unreg_isa_device;
+
+	return 0;
+
+ exit_unreg_isa_device:
+	lm78_isa_unregister();
+ exit:
+	return res;
+}
+
+static void __exit sm_lm78_exit(void)
+{
+	lm78_isa_unregister();
+	i2c_del_driver(&lm78_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard, Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("LM78/LM79 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sm_lm78_init);
+module_exit(sm_lm78_exit);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
new file mode 100644
index 0000000..4bcd9b8
--- /dev/null
+++ b/drivers/hwmon/lm80.c
@@ -0,0 +1,674 @@
+/*
+ * lm80.c - From lm_sensors, Linux kernel modules for hardware
+ *	    monitoring
+ * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *			     and Philip Edelbrock <phil@netroedge.com>
+ *
+ * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org>
+ *
+ * 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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+						0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Many LM80 constants specified below */
+
+/* The LM80 registers */
+#define LM80_REG_IN_MAX(nr)		(0x2a + (nr) * 2)
+#define LM80_REG_IN_MIN(nr)		(0x2b + (nr) * 2)
+#define LM80_REG_IN(nr)			(0x20 + (nr))
+
+#define LM80_REG_FAN1			0x28
+#define LM80_REG_FAN2			0x29
+#define LM80_REG_FAN_MIN(nr)		(0x3b + (nr))
+
+#define LM80_REG_TEMP			0x27
+#define LM80_REG_TEMP_HOT_MAX		0x38
+#define LM80_REG_TEMP_HOT_HYST		0x39
+#define LM80_REG_TEMP_OS_MAX		0x3a
+#define LM80_REG_TEMP_OS_HYST		0x3b
+
+#define LM80_REG_CONFIG			0x00
+#define LM80_REG_ALARM1			0x01
+#define LM80_REG_ALARM2			0x02
+#define LM80_REG_MASK1			0x03
+#define LM80_REG_MASK2			0x04
+#define LM80_REG_FANDIV			0x05
+#define LM80_REG_RES			0x06
+
+#define LM96080_REG_CONV_RATE		0x07
+#define LM96080_REG_MAN_ID		0x3e
+#define LM96080_REG_DEV_ID		0x3f
+
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ * Fixing this is just not worth it.
+ */
+
+#define IN_TO_REG(val)		(clamp_val(((val) + 5) / 10, 0, 255))
+#define IN_FROM_REG(val)	((val) * 10)
+
+static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val, div)	((val) == 0 ? -1 : \
+				(val) == 255 ? 0 : 1350000/((div) * (val)))
+
+#define TEMP_FROM_REG(reg)	((reg) * 125 / 32)
+#define TEMP_TO_REG(temp)	(DIV_ROUND_CLOSEST(clamp_val((temp), \
+					-128000, 127000), 1000) << 8)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+
+enum temp_index {
+	t_input = 0,
+	t_hot_max,
+	t_hot_hyst,
+	t_os_max,
+	t_os_hyst,
+	t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+	[t_input] = LM80_REG_TEMP,
+	[t_hot_max] = LM80_REG_TEMP_HOT_MAX,
+	[t_hot_hyst] = LM80_REG_TEMP_HOT_HYST,
+	[t_os_max] = LM80_REG_TEMP_OS_MAX,
+	[t_os_hyst] = LM80_REG_TEMP_OS_HYST,
+};
+
+enum in_index {
+	i_input = 0,
+	i_max,
+	i_min,
+	i_num_in
+};
+
+enum fan_index {
+	f_input,
+	f_min,
+	f_num_fan
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm80_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char error;		/* !=0 if error occurred during last update */
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[i_num_in][7];	/* Register value, 1st index is enum in_index */
+	u8 fan[f_num_fan][2];	/* Register value, 1st index enum fan_index */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	s16 temp[t_num_temp];	/* Register values, normalized to 16 bit */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+static int lm80_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* Called when we have found a new LM80 and after read errors */
+static void lm80_init_client(struct i2c_client *client)
+{
+	/*
+	 * Reset all except Watchdog values and last conversion values
+	 * This sets fan-divs to 2, among others. This makes most other
+	 * initializations unnecessary
+	 */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x80);
+	/* Set 11-bit temperature resolution */
+	lm80_write_value(client, LM80_REG_RES, 0x08);
+
+	/* Start monitoring */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x01);
+}
+
+static struct lm80_data *lm80_update_device(struct device *dev)
+{
+	struct lm80_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+	int rv;
+	int prev_rv;
+	struct lm80_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->error)
+		lm80_init_client(client);
+
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+		dev_dbg(dev, "Starting lm80 update\n");
+		for (i = 0; i <= 6; i++) {
+			rv = lm80_read_value(client, LM80_REG_IN(i));
+			if (rv < 0)
+				goto abort;
+			data->in[i_input][i] = rv;
+
+			rv = lm80_read_value(client, LM80_REG_IN_MIN(i));
+			if (rv < 0)
+				goto abort;
+			data->in[i_min][i] = rv;
+
+			rv = lm80_read_value(client, LM80_REG_IN_MAX(i));
+			if (rv < 0)
+				goto abort;
+			data->in[i_max][i] = rv;
+		}
+
+		rv = lm80_read_value(client, LM80_REG_FAN1);
+		if (rv < 0)
+			goto abort;
+		data->fan[f_input][0] = rv;
+
+		rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+		if (rv < 0)
+			goto abort;
+		data->fan[f_min][0] = rv;
+
+		rv = lm80_read_value(client, LM80_REG_FAN2);
+		if (rv < 0)
+			goto abort;
+		data->fan[f_input][1] = rv;
+
+		rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+		if (rv < 0)
+			goto abort;
+		data->fan[f_min][1] = rv;
+
+		prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP);
+		if (rv < 0)
+			goto abort;
+		rv = lm80_read_value(client, LM80_REG_RES);
+		if (rv < 0)
+			goto abort;
+		data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0);
+
+		for (i = t_input + 1; i < t_num_temp; i++) {
+			rv = lm80_read_value(client, temp_regs[i]);
+			if (rv < 0)
+				goto abort;
+			data->temp[i] = rv << 8;
+		}
+
+		rv = lm80_read_value(client, LM80_REG_FANDIV);
+		if (rv < 0)
+			goto abort;
+		data->fan_div[0] = (rv >> 2) & 0x03;
+		data->fan_div[1] = (rv >> 4) & 0x03;
+
+		prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1);
+		if (rv < 0)
+			goto abort;
+		rv = lm80_read_value(client, LM80_REG_ALARM2);
+		if (rv < 0)
+			goto abort;
+		data->alarms = prev_rv + (rv << 8);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+		data->error = 0;
+	}
+	goto done;
+
+abort:
+	ret = ERR_PTR(rv);
+	data->valid = 0;
+	data->error = 1;
+
+done:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct lm80_data *data = lm80_update_device(dev);
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index]));
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct lm80_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	long val;
+	u8 reg;
+	int err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index);
+
+	mutex_lock(&data->update_lock);
+	data->in[nr][index] = IN_TO_REG(val);
+	lm80_write_value(client, reg, data->in[nr][index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index],
+		       DIV_FROM_REG(data->fan_div[index])));
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	struct lm80_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan[nr][index] = FAN_TO_REG(val,
+					  DIV_FROM_REG(data->fan_div[index]));
+	lm80_write_value(client, LM80_REG_FAN_MIN(index + 1),
+			 data->fan[nr][index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm80_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long min, val;
+	u8 reg;
+	int err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* Save fan_min */
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan[f_min][nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	switch (val) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		dev_err(dev,
+			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+			val);
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	reg = (lm80_read_value(client, LM80_REG_FANDIV) &
+	       ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1)));
+	lm80_write_value(client, LM80_REG_FANDIV, reg);
+
+	/* Restore fan_min */
+	data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1),
+			 data->fan[f_min][nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+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 lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm80_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long val;
+	int err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = TEMP_TO_REG(val);
+	lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 2);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 3);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 4);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 5);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_min, 6);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 0);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 3);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 4);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 5);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+		show_in, set_in, i_max, 6);
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, i_input, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, i_input, 1);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, i_input, 2);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5);
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IWUSR | S_IRUGO,
+		show_fan, set_fan_min, f_min, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IWUSR | S_IRUGO,
+		show_fan, set_fan_min, f_min, 1);
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, f_input, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, f_input, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+		show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+		show_fan_div, set_fan_div, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+		set_temp, t_hot_max);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp,
+		set_temp, t_hot_hyst);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+		set_temp, t_os_max);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp,
+		set_temp, t_os_hyst);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+/*
+ * Real code
+ */
+
+static struct attribute *lm80_attrs[] = {
+	&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_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_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm80);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int i, cur, man_id, dev_id;
+	const char *name = NULL;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* First check for unused bits, common to both chip types */
+	if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
+	 || (lm80_read_value(client, LM80_REG_CONFIG) & 0x80))
+		return -ENODEV;
+
+	/*
+	 * The LM96080 has manufacturer and stepping/die rev registers so we
+	 * can just check that. The LM80 does not have such registers so we
+	 * have to use a more expensive trick.
+	 */
+	man_id = lm80_read_value(client, LM96080_REG_MAN_ID);
+	dev_id = lm80_read_value(client, LM96080_REG_DEV_ID);
+	if (man_id == 0x01 && dev_id == 0x08) {
+		/* Check more unused bits for confirmation */
+		if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe)
+			return -ENODEV;
+
+		name = "lm96080";
+	} else {
+		/* Check 6-bit addressing */
+		for (i = 0x2a; i <= 0x3d; i++) {
+			cur = i2c_smbus_read_byte_data(client, i);
+			if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
+			 || (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
+			 || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
+				return -ENODEV;
+		}
+
+		name = "lm80";
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int lm80_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm80_data *data;
+
+	data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM80 chip */
+	lm80_init_client(client);
+
+	/* A few vars need to be filled upon startup */
+	data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+	data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, lm80_groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id lm80_id[] = {
+	{ "lm80", 0 },
+	{ "lm96080", 1 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm80_id);
+
+static struct i2c_driver lm80_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm80",
+	},
+	.probe		= lm80_probe,
+	.id_table	= lm80_id,
+	.detect		= lm80_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm80_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+	"Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("LM80 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
new file mode 100644
index 0000000..9e4d0e1
--- /dev/null
+++ b/drivers/hwmon/lm83.c
@@ -0,0 +1,389 @@
+/*
+ * lm83.c - Part of lm_sensors, Linux kernel modules for hardware
+ *          monitoring
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
+ *
+ * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
+ * a sensor chip made by National Semiconductor. It reports up to four
+ * temperatures (its own plus up to three external ones) with a 1 deg
+ * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained
+ * from National's website at:
+ *   http://www.national.com/pf/LM/LM83.html
+ * Since the datasheet omits to give the chip stepping code, I give it
+ * here: 0x03 (at register 0xff).
+ *
+ * Also supports the LM82 temp sensor, which is basically a stripped down
+ * model of the LM83.  Datasheet is here:
+ * http://www.national.com/pf/LM/LM82.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/*
+ * Addresses to scan
+ * Address is selected using 2 three-level pins, resulting in 9 possible
+ * addresses.
+ */
+
+static const unsigned short normal_i2c[] = {
+	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+enum chips { lm83, lm82 };
+
+/*
+ * The LM83 registers
+ * Manufacturer ID is 0x01 for National Semiconductor.
+ */
+
+#define LM83_REG_R_MAN_ID		0xFE
+#define LM83_REG_R_CHIP_ID		0xFF
+#define LM83_REG_R_CONFIG		0x03
+#define LM83_REG_W_CONFIG		0x09
+#define LM83_REG_R_STATUS1		0x02
+#define LM83_REG_R_STATUS2		0x35
+#define LM83_REG_R_LOCAL_TEMP		0x00
+#define LM83_REG_R_LOCAL_HIGH		0x05
+#define LM83_REG_W_LOCAL_HIGH		0x0B
+#define LM83_REG_R_REMOTE1_TEMP		0x30
+#define LM83_REG_R_REMOTE1_HIGH		0x38
+#define LM83_REG_W_REMOTE1_HIGH		0x50
+#define LM83_REG_R_REMOTE2_TEMP		0x01
+#define LM83_REG_R_REMOTE2_HIGH		0x07
+#define LM83_REG_W_REMOTE2_HIGH		0x0D
+#define LM83_REG_R_REMOTE3_TEMP		0x31
+#define LM83_REG_R_REMOTE3_HIGH		0x3A
+#define LM83_REG_W_REMOTE3_HIGH		0x52
+#define LM83_REG_R_TCRIT		0x42
+#define LM83_REG_W_TCRIT		0x5A
+
+/*
+ * Conversions and various macros
+ * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius.
+ */
+
+#define TEMP_FROM_REG(val)	((val) * 1000)
+#define TEMP_TO_REG(val)	((val) <= -128000 ? -128 : \
+				 (val) >= 127000 ? 127 : \
+				 (val) < 0 ? ((val) - 500) / 1000 : \
+				 ((val) + 500) / 1000)
+
+static const u8 LM83_REG_R_TEMP[] = {
+	LM83_REG_R_LOCAL_TEMP,
+	LM83_REG_R_REMOTE1_TEMP,
+	LM83_REG_R_REMOTE2_TEMP,
+	LM83_REG_R_REMOTE3_TEMP,
+	LM83_REG_R_LOCAL_HIGH,
+	LM83_REG_R_REMOTE1_HIGH,
+	LM83_REG_R_REMOTE2_HIGH,
+	LM83_REG_R_REMOTE3_HIGH,
+	LM83_REG_R_TCRIT,
+};
+
+static const u8 LM83_REG_W_HIGH[] = {
+	LM83_REG_W_LOCAL_HIGH,
+	LM83_REG_W_REMOTE1_HIGH,
+	LM83_REG_W_REMOTE2_HIGH,
+	LM83_REG_W_REMOTE3_HIGH,
+	LM83_REG_W_TCRIT,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm83_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	s8 temp[9];	/* 0..3: input 1-4,
+			   4..7: high limit 1-4,
+			   8   : critical limit */
+	u16 alarms; /* bitvector, combined */
+};
+
+static struct lm83_data *lm83_update_device(struct device *dev)
+{
+	struct lm83_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+		int nr;
+
+		dev_dbg(&client->dev, "Updating lm83 data.\n");
+		for (nr = 0; nr < 9; nr++) {
+			data->temp[nr] =
+			    i2c_smbus_read_byte_data(client,
+			    LM83_REG_R_TEMP[nr]);
+		}
+		data->alarms =
+		    i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
+		    + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
+		    << 8);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+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 lm83_data *data = lm83_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm83_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int nr = attr->index;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
+				  data->temp[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+			   char *buf)
+{
+	struct lm83_data *data = lm83_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm83_data *data = lm83_update_device(dev);
+	int bitnr = attr->index;
+
+	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+	set_temp, 4);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+	set_temp, 5);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp,
+	set_temp, 6);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp,
+	set_temp, 7);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+	set_temp, 8);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
+/* Raw alarm file for compatibility */
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm83_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	NULL
+};
+
+static const struct attribute_group lm83_group = {
+	.attrs = lm83_attributes,
+};
+
+static struct attribute *lm83_attributes_opt[] = {
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm83_group_opt = {
+	.attrs = lm83_attributes_opt,
+};
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm83_detect(struct i2c_client *new_client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	const char *name;
+	u8 man_id, chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Detection */
+	if ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) & 0xA8) ||
+	    (i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) & 0x48) ||
+	    (i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) & 0x41)) {
+		dev_dbg(&adapter->dev, "LM83 detection failed at 0x%02x\n",
+			new_client->addr);
+		return -ENODEV;
+	}
+
+	/* Identification */
+	man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID);
+	if (man_id != 0x01)	/* National Semiconductor */
+		return -ENODEV;
+
+	chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID);
+	switch (chip_id) {
+	case 0x03:
+		name = "lm83";
+		break;
+	case 0x01:
+		name = "lm82";
+		break;
+	default:
+		/* identification failed */
+		dev_info(&adapter->dev,
+			 "Unsupported chip (man_id=0x%02X, chip_id=0x%02X)\n",
+			 man_id, chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int lm83_probe(struct i2c_client *new_client,
+		      const struct i2c_device_id *id)
+{
+	struct device *hwmon_dev;
+	struct lm83_data *data;
+
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm83_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = new_client;
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Register sysfs hooks
+	 * The LM82 can only monitor one external diode which is
+	 * at the same register as the LM83 temp3 entry - so we
+	 * declare 1 and 3 common, and then 2 and 4 only for the LM83.
+	 */
+	data->groups[0] = &lm83_group;
+	if (id->driver_data == lm83)
+		data->groups[1] = &lm83_group_opt;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+							   new_client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id lm83_id[] = {
+	{ "lm83", lm83 },
+	{ "lm82", lm82 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm83_id);
+
+static struct i2c_driver lm83_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm83",
+	},
+	.probe		= lm83_probe,
+	.id_table	= lm83_id,
+	.detect		= lm83_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm83_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("LM83 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
new file mode 100644
index 0000000..6ff773f
--- /dev/null
+++ b/drivers/hwmon/lm85.c
@@ -0,0 +1,1642 @@
+/*
+ * lm85.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	    monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ * Copyright (c) 2002, 2003  Philip Pokorny <ppokorny@penguincomputing.com>
+ * Copyright (c) 2003        Margit Schubert-While <margitsw@t-online.de>
+ * Copyright (c) 2004        Justin Thiessen <jthiessen@penguincomputing.com>
+ * Copyright (C) 2007--2014  Jean Delvare <jdelvare@suse.de>
+ *
+ * Chip details at	      <http://www.national.com/ds/LM/LM85.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-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/util_macros.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips {
+	lm85,
+	adm1027, adt7463, adt7468,
+	emc6d100, emc6d102, emc6d103, emc6d103s
+};
+
+/* The LM85 registers */
+
+#define LM85_REG_IN(nr)			(0x20 + (nr))
+#define LM85_REG_IN_MIN(nr)		(0x44 + (nr) * 2)
+#define LM85_REG_IN_MAX(nr)		(0x45 + (nr) * 2)
+
+#define LM85_REG_TEMP(nr)		(0x25 + (nr))
+#define LM85_REG_TEMP_MIN(nr)		(0x4e + (nr) * 2)
+#define LM85_REG_TEMP_MAX(nr)		(0x4f + (nr) * 2)
+
+/* Fan speeds are LSB, MSB (2 bytes) */
+#define LM85_REG_FAN(nr)		(0x28 + (nr) * 2)
+#define LM85_REG_FAN_MIN(nr)		(0x54 + (nr) * 2)
+
+#define LM85_REG_PWM(nr)		(0x30 + (nr))
+
+#define LM85_REG_COMPANY		0x3e
+#define LM85_REG_VERSTEP		0x3f
+
+#define ADT7468_REG_CFG5		0x7c
+#define ADT7468_OFF64			(1 << 0)
+#define ADT7468_HFPWM			(1 << 1)
+#define IS_ADT7468_OFF64(data)		\
+	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
+#define IS_ADT7468_HFPWM(data)		\
+	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_HFPWM))
+
+/* These are the recognized values for the above regs */
+#define LM85_COMPANY_NATIONAL		0x01
+#define LM85_COMPANY_ANALOG_DEV		0x41
+#define LM85_COMPANY_SMSC		0x5c
+#define LM85_VERSTEP_LM85C		0x60
+#define LM85_VERSTEP_LM85B		0x62
+#define LM85_VERSTEP_LM96000_1		0x68
+#define LM85_VERSTEP_LM96000_2		0x69
+#define LM85_VERSTEP_ADM1027		0x60
+#define LM85_VERSTEP_ADT7463		0x62
+#define LM85_VERSTEP_ADT7463C		0x6A
+#define LM85_VERSTEP_ADT7468_1		0x71
+#define LM85_VERSTEP_ADT7468_2		0x72
+#define LM85_VERSTEP_EMC6D100_A0        0x60
+#define LM85_VERSTEP_EMC6D100_A1        0x61
+#define LM85_VERSTEP_EMC6D102		0x65
+#define LM85_VERSTEP_EMC6D103_A0	0x68
+#define LM85_VERSTEP_EMC6D103_A1	0x69
+#define LM85_VERSTEP_EMC6D103S		0x6A	/* Also known as EMC6D103:A2 */
+
+#define LM85_REG_CONFIG			0x40
+
+#define LM85_REG_ALARM1			0x41
+#define LM85_REG_ALARM2			0x42
+
+#define LM85_REG_VID			0x43
+
+/* Automated FAN control */
+#define LM85_REG_AFAN_CONFIG(nr)	(0x5c + (nr))
+#define LM85_REG_AFAN_RANGE(nr)		(0x5f + (nr))
+#define LM85_REG_AFAN_SPIKE1		0x62
+#define LM85_REG_AFAN_MINPWM(nr)	(0x64 + (nr))
+#define LM85_REG_AFAN_LIMIT(nr)		(0x67 + (nr))
+#define LM85_REG_AFAN_CRITICAL(nr)	(0x6a + (nr))
+#define LM85_REG_AFAN_HYST1		0x6d
+#define LM85_REG_AFAN_HYST2		0x6e
+
+#define ADM1027_REG_EXTEND_ADC1		0x76
+#define ADM1027_REG_EXTEND_ADC2		0x77
+
+#define EMC6D100_REG_ALARM3             0x7d
+/* IN5, IN6 and IN7 */
+#define EMC6D100_REG_IN(nr)             (0x70 + ((nr) - 5))
+#define EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr) - 5) * 2)
+#define EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr) - 5) * 2)
+#define EMC6D102_REG_EXTEND_ADC1	0x85
+#define EMC6D102_REG_EXTEND_ADC2	0x86
+#define EMC6D102_REG_EXTEND_ADC3	0x87
+#define EMC6D102_REG_EXTEND_ADC4	0x88
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ */
+
+/* IN are scaled according to built-in resistors */
+static const int lm85_scaling[] = {  /* .001 Volts */
+	2500, 2250, 3300, 5000, 12000,
+	3300, 1500, 1800 /*EMC6D100*/
+};
+#define SCALE(val, from, to)	(((val) * (to) + ((from) / 2)) / (from))
+
+#define INS_TO_REG(n, val)	\
+		clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255)
+
+#define INSEXT_FROM_REG(n, val, ext)	\
+		SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
+
+#define INS_FROM_REG(n, val)	SCALE((val), 192, lm85_scaling[n])
+
+/* FAN speed is measured using 90kHz clock */
+static inline u16 FAN_TO_REG(unsigned long val)
+{
+	if (!val)
+		return 0xffff;
+	return clamp_val(5400000 / val, 1, 0xfffe);
+}
+#define FAN_FROM_REG(val)	((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
+				 5400000 / (val))
+
+/* Temperature is reported in .001 degC increments */
+#define TEMP_TO_REG(val)	\
+		DIV_ROUND_CLOSEST(clamp_val((val), -127000, 127000), 1000)
+#define TEMPEXT_FROM_REG(val, ext)	\
+		SCALE(((val) << 4) + (ext), 16, 1000)
+#define TEMP_FROM_REG(val)	((val) * 1000)
+
+#define PWM_TO_REG(val)			clamp_val(val, 0, 255)
+#define PWM_FROM_REG(val)		(val)
+
+
+/*
+ * ZONEs have the following parameters:
+ *    Limit (low) temp,           1. degC
+ *    Hysteresis (below limit),   1. degC (0-15)
+ *    Range of speed control,     .1 degC (2-80)
+ *    Critical (high) temp,       1. degC
+ *
+ * FAN PWMs have the following parameters:
+ *    Reference Zone,                 1, 2, 3, etc.
+ *    Spinup time,                    .05 sec
+ *    PWM value at limit/low temp,    1 count
+ *    PWM Frequency,                  1. Hz
+ *    PWM is Min or OFF below limit,  flag
+ *    Invert PWM output,              flag
+ *
+ * Some chips filter the temp, others the fan.
+ *    Filter constant (or disabled)   .1 seconds
+ */
+
+/* These are the zone temperature range encodings in .001 degree C */
+static const int lm85_range_map[] = {
+	2000, 2500, 3300, 4000, 5000, 6600, 8000, 10000,
+	13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000
+};
+
+static int RANGE_TO_REG(long range)
+{
+	return find_closest(range, lm85_range_map, ARRAY_SIZE(lm85_range_map));
+}
+#define RANGE_FROM_REG(val)	lm85_range_map[(val) & 0x0f]
+
+/* These are the PWM frequency encodings */
+static const int lm85_freq_map[8] = { /* 1 Hz */
+	10, 15, 23, 30, 38, 47, 61, 94
+};
+static const int adm1027_freq_map[8] = { /* 1 Hz */
+	11, 15, 22, 29, 35, 44, 59, 88
+};
+#define FREQ_MAP_LEN	8
+
+static int FREQ_TO_REG(const int *map,
+		       unsigned int map_size, unsigned long freq)
+{
+	return find_closest(freq, map, map_size);
+}
+
+static int FREQ_FROM_REG(const int *map, u8 reg)
+{
+	return map[reg & 0x07];
+}
+
+/*
+ * Since we can't use strings, I'm abusing these numbers
+ *   to stand in for the following meanings:
+ *      1 -- PWM responds to Zone 1
+ *      2 -- PWM responds to Zone 2
+ *      3 -- PWM responds to Zone 3
+ *     23 -- PWM responds to the higher temp of Zone 2 or 3
+ *    123 -- PWM responds to highest of Zone 1, 2, or 3
+ *      0 -- PWM is always at 0% (ie, off)
+ *     -1 -- PWM is always at 100%
+ *     -2 -- PWM responds to manual control
+ */
+
+static const int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 };
+#define ZONE_FROM_REG(val)	lm85_zone_map[(val) >> 5]
+
+static int ZONE_TO_REG(int zone)
+{
+	int i;
+
+	for (i = 0; i <= 7; ++i)
+		if (zone == lm85_zone_map[i])
+			break;
+	if (i > 7)   /* Not found. */
+		i = 3;  /* Always 100% */
+	return i << 5;
+}
+
+#define HYST_TO_REG(val)	clamp_val(((val) + 500) / 1000, 0, 15)
+#define HYST_FROM_REG(val)	((val) * 1000)
+
+/*
+ * Chip sampling rates
+ *
+ * Some sensors are not updated more frequently than once per second
+ *    so it doesn't make sense to read them more often than that.
+ *    We cache the results and return the saved data if the driver
+ *    is called again before a second has elapsed.
+ *
+ * Also, there is significant configuration data for this chip
+ *    given the automatic PWM fan control that is possible.  There
+ *    are about 47 bytes of config data to only 22 bytes of actual
+ *    readings.  So, we keep the config data up to date in the cache
+ *    when it is written and only sample it once every 1 *minute*
+ */
+#define LM85_DATA_INTERVAL  (HZ + HZ / 2)
+#define LM85_CONFIG_INTERVAL  (1 * 60 * HZ)
+
+/*
+ * LM85 can automatically adjust fan speeds based on temperature
+ * This structure encapsulates an entire Zone config.  There are
+ * three zones (one for each temperature input) on the lm85
+ */
+struct lm85_zone {
+	s8 limit;	/* Low temp limit */
+	u8 hyst;	/* Low limit hysteresis. (0-15) */
+	u8 range;	/* Temp range, encoded */
+	s8 critical;	/* "All fans ON" temp limit */
+	u8 max_desired; /*
+			 * Actual "max" temperature specified.  Preserved
+			 * to prevent "drift" as other autofan control
+			 * values change.
+			 */
+};
+
+struct lm85_autofan {
+	u8 config;	/* Register value */
+	u8 min_pwm;	/* Minimum PWM value, encoded */
+	u8 min_off;	/* Min PWM or OFF below "limit", flag */
+};
+
+/*
+ * For each registered chip, we need to keep some data in memory.
+ * The structure is dynamically allocated.
+ */
+struct lm85_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[6];
+	const int *freq_map;
+	enum chips type;
+
+	bool has_vid5;	/* true if VID5 is configured for ADT7463 or ADT7468 */
+
+	struct mutex update_lock;
+	int valid;		/* !=0 if following fields are valid */
+	unsigned long last_reading;	/* In jiffies */
+	unsigned long last_config;	/* In jiffies */
+
+	u8 in[8];		/* Register value */
+	u8 in_max[8];		/* Register value */
+	u8 in_min[8];		/* Register value */
+	s8 temp[3];		/* Register value */
+	s8 temp_min[3];		/* Register value */
+	s8 temp_max[3];		/* Register value */
+	u16 fan[4];		/* Register value */
+	u16 fan_min[4];		/* Register value */
+	u8 pwm[3];		/* Register value */
+	u8 pwm_freq[3];		/* Register encoding */
+	u8 temp_ext[3];		/* Decoded values */
+	u8 in_ext[8];		/* Decoded values */
+	u8 vid;			/* Register value */
+	u8 vrm;			/* VRM version */
+	u32 alarms;		/* Register encoding, combined */
+	u8 cfg5;		/* Config Register 5 on ADT7468 */
+	struct lm85_autofan autofan[3];
+	struct lm85_zone zone[3];
+};
+
+static int lm85_read_value(struct i2c_client *client, u8 reg)
+{
+	int res;
+
+	/* What size location is it? */
+	switch (reg) {
+	case LM85_REG_FAN(0):  /* Read WORD data */
+	case LM85_REG_FAN(1):
+	case LM85_REG_FAN(2):
+	case LM85_REG_FAN(3):
+	case LM85_REG_FAN_MIN(0):
+	case LM85_REG_FAN_MIN(1):
+	case LM85_REG_FAN_MIN(2):
+	case LM85_REG_FAN_MIN(3):
+	case LM85_REG_ALARM1:	/* Read both bytes at once */
+		res = i2c_smbus_read_byte_data(client, reg) & 0xff;
+		res |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
+		break;
+	default:	/* Read BYTE data */
+		res = i2c_smbus_read_byte_data(client, reg);
+		break;
+	}
+
+	return res;
+}
+
+static void lm85_write_value(struct i2c_client *client, u8 reg, int value)
+{
+	switch (reg) {
+	case LM85_REG_FAN(0):  /* Write WORD data */
+	case LM85_REG_FAN(1):
+	case LM85_REG_FAN(2):
+	case LM85_REG_FAN(3):
+	case LM85_REG_FAN_MIN(0):
+	case LM85_REG_FAN_MIN(1):
+	case LM85_REG_FAN_MIN(2):
+	case LM85_REG_FAN_MIN(3):
+	/* NOTE: ALARM is read only, so not included here */
+		i2c_smbus_write_byte_data(client, reg, value & 0xff);
+		i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+		break;
+	default:	/* Write BYTE data */
+		i2c_smbus_write_byte_data(client, reg, value);
+		break;
+	}
+}
+
+static struct lm85_data *lm85_update_device(struct device *dev)
+{
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid ||
+	     time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL)) {
+		/* Things that change quickly */
+		dev_dbg(&client->dev, "Reading sensor values\n");
+
+		/*
+		 * Have to read extended bits first to "freeze" the
+		 * more significant bits that are read later.
+		 * There are 2 additional resolution bits per channel and we
+		 * have room for 4, so we shift them to the left.
+		 */
+		if (data->type == adm1027 || data->type == adt7463 ||
+		    data->type == adt7468) {
+			int ext1 = lm85_read_value(client,
+						   ADM1027_REG_EXTEND_ADC1);
+			int ext2 =  lm85_read_value(client,
+						    ADM1027_REG_EXTEND_ADC2);
+			int val = (ext1 << 8) + ext2;
+
+			for (i = 0; i <= 4; i++)
+				data->in_ext[i] =
+					((val >> (i * 2)) & 0x03) << 2;
+
+			for (i = 0; i <= 2; i++)
+				data->temp_ext[i] =
+					(val >> ((i + 4) * 2)) & 0x0c;
+		}
+
+		data->vid = lm85_read_value(client, LM85_REG_VID);
+
+		for (i = 0; i <= 3; ++i) {
+			data->in[i] =
+			    lm85_read_value(client, LM85_REG_IN(i));
+			data->fan[i] =
+			    lm85_read_value(client, LM85_REG_FAN(i));
+		}
+
+		if (!data->has_vid5)
+			data->in[4] = lm85_read_value(client, LM85_REG_IN(4));
+
+		if (data->type == adt7468)
+			data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
+
+		for (i = 0; i <= 2; ++i) {
+			data->temp[i] =
+			    lm85_read_value(client, LM85_REG_TEMP(i));
+			data->pwm[i] =
+			    lm85_read_value(client, LM85_REG_PWM(i));
+
+			if (IS_ADT7468_OFF64(data))
+				data->temp[i] -= 64;
+		}
+
+		data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
+
+		if (data->type == emc6d100) {
+			/* Three more voltage sensors */
+			for (i = 5; i <= 7; ++i) {
+				data->in[i] = lm85_read_value(client,
+							EMC6D100_REG_IN(i));
+			}
+			/* More alarm bits */
+			data->alarms |= lm85_read_value(client,
+						EMC6D100_REG_ALARM3) << 16;
+		} else if (data->type == emc6d102 || data->type == emc6d103 ||
+			   data->type == emc6d103s) {
+			/*
+			 * Have to read LSB bits after the MSB ones because
+			 * the reading of the MSB bits has frozen the
+			 * LSBs (backward from the ADM1027).
+			 */
+			int ext1 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC1);
+			int ext2 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC2);
+			int ext3 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC3);
+			int ext4 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC4);
+			data->in_ext[0] = ext3 & 0x0f;
+			data->in_ext[1] = ext4 & 0x0f;
+			data->in_ext[2] = ext4 >> 4;
+			data->in_ext[3] = ext3 >> 4;
+			data->in_ext[4] = ext2 >> 4;
+
+			data->temp_ext[0] = ext1 & 0x0f;
+			data->temp_ext[1] = ext2 & 0x0f;
+			data->temp_ext[2] = ext1 >> 4;
+		}
+
+		data->last_reading = jiffies;
+	}  /* last_reading */
+
+	if (!data->valid ||
+	     time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL)) {
+		/* Things that don't change often */
+		dev_dbg(&client->dev, "Reading config values\n");
+
+		for (i = 0; i <= 3; ++i) {
+			data->in_min[i] =
+			    lm85_read_value(client, LM85_REG_IN_MIN(i));
+			data->in_max[i] =
+			    lm85_read_value(client, LM85_REG_IN_MAX(i));
+			data->fan_min[i] =
+			    lm85_read_value(client, LM85_REG_FAN_MIN(i));
+		}
+
+		if (!data->has_vid5)  {
+			data->in_min[4] = lm85_read_value(client,
+					  LM85_REG_IN_MIN(4));
+			data->in_max[4] = lm85_read_value(client,
+					  LM85_REG_IN_MAX(4));
+		}
+
+		if (data->type == emc6d100) {
+			for (i = 5; i <= 7; ++i) {
+				data->in_min[i] = lm85_read_value(client,
+						EMC6D100_REG_IN_MIN(i));
+				data->in_max[i] = lm85_read_value(client,
+						EMC6D100_REG_IN_MAX(i));
+			}
+		}
+
+		for (i = 0; i <= 2; ++i) {
+			int val;
+
+			data->temp_min[i] =
+			    lm85_read_value(client, LM85_REG_TEMP_MIN(i));
+			data->temp_max[i] =
+			    lm85_read_value(client, LM85_REG_TEMP_MAX(i));
+
+			data->autofan[i].config =
+			    lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
+			val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
+			data->pwm_freq[i] = val & 0x07;
+			data->zone[i].range = val >> 4;
+			data->autofan[i].min_pwm =
+			    lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
+			data->zone[i].limit =
+			    lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
+			data->zone[i].critical =
+			    lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
+
+			if (IS_ADT7468_OFF64(data)) {
+				data->temp_min[i] -= 64;
+				data->temp_max[i] -= 64;
+				data->zone[i].limit -= 64;
+				data->zone[i].critical -= 64;
+			}
+		}
+
+		if (data->type != emc6d103s) {
+			i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
+			data->autofan[0].min_off = (i & 0x20) != 0;
+			data->autofan[1].min_off = (i & 0x40) != 0;
+			data->autofan[2].min_off = (i & 0x80) != 0;
+
+			i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
+			data->zone[0].hyst = i >> 4;
+			data->zone[1].hyst = i & 0x0f;
+
+			i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
+			data->zone[2].hyst = i >> 4;
+		}
+
+		data->last_config = jiffies;
+	}  /* last_config */
+
+	data->valid = 1;
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* 4 Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr]));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val);
+	lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_fan_offset(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1)
+
+show_fan_offset(1);
+show_fan_offset(2);
+show_fan_offset(3);
+show_fan_offset(4);
+
+/* vid, vrm, alarms */
+
+static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	int vid;
+
+	if (data->has_vid5) {
+		/* 6-pin VID (VRM 10) */
+		vid = vid_from_reg(data->vid & 0x3f, data->vrm);
+	} else {
+		/* 5-pin VID (VRM 9) */
+		vid = vid_from_reg(data->vid & 0x1f, data->vrm);
+	}
+
+	return sprintf(buf, "%d\n", vid);
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct lm85_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%ld\n", (long) data->vrm);
+}
+
+static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct lm85_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t show_alarms_reg(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+/* pwm */
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = PWM_TO_REG(val);
+	lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	int pwm_zone, enable;
+
+	pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
+	switch (pwm_zone) {
+	case -1:	/* PWM is always at 100% */
+		enable = 0;
+		break;
+	case 0:		/* PWM is always at 0% */
+	case -2:	/* PWM responds to manual control */
+		enable = 1;
+		break;
+	default:	/* PWM in automatic mode */
+		enable = 2;
+	}
+	return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+		*attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 config;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	switch (val) {
+	case 0:
+		config = 3;
+		break;
+	case 1:
+		config = 7;
+		break;
+	case 2:
+		/*
+		 * Here we have to choose arbitrarily one of the 5 possible
+		 * configurations; I go for the safest
+		 */
+		config = 6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->autofan[nr].config = lm85_read_value(client,
+		LM85_REG_AFAN_CONFIG(nr));
+	data->autofan[nr].config = (data->autofan[nr].config & ~0xe0)
+		| (config << 5);
+	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+		data->autofan[nr].config);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_freq(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	int freq;
+
+	if (IS_ADT7468_HFPWM(data))
+		freq = 22500;
+	else
+		freq = FREQ_FROM_REG(data->freq_map, data->pwm_freq[nr]);
+
+	return sprintf(buf, "%d\n", freq);
+}
+
+static ssize_t set_pwm_freq(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/*
+	 * The ADT7468 has a special high-frequency PWM output mode,
+	 * where all PWM outputs are driven by a 22.5 kHz clock.
+	 * This might confuse the user, but there's not much we can do.
+	 */
+	if (data->type == adt7468 && val >= 11300) {	/* High freq. mode */
+		data->cfg5 &= ~ADT7468_HFPWM;
+		lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+	} else {					/* Low freq. mode */
+		data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map,
+						 FREQ_MAP_LEN, val);
+		lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+				 (data->zone[nr].range << 4)
+				 | data->pwm_freq[nr]);
+		if (data->type == adt7468) {
+			data->cfg5 |= ADT7468_HFPWM;
+			lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_pwm_reg(offset)						\
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,		\
+		show_pwm, set_pwm, offset - 1);				\
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,	\
+		show_pwm_enable, set_pwm_enable, offset - 1);		\
+static SENSOR_DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR,	\
+		show_pwm_freq, set_pwm_freq, offset - 1)
+
+show_pwm_reg(1);
+show_pwm_reg(2);
+show_pwm_reg(3);
+
+/* Voltages */
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", INSEXT_FROM_REG(nr, data->in[nr],
+						    data->in_ext[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = INS_TO_REG(nr, val);
+	lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = INS_TO_REG(nr, val);
+	lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_in_reg(offset)						\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,			\
+		show_in, NULL, offset);					\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_in_min, set_in_min, offset);			\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
+		show_in_max, set_in_max, offset)
+
+show_in_reg(0);
+show_in_reg(1);
+show_in_reg(2);
+show_in_reg(3);
+show_in_reg(4);
+show_in_reg(5);
+show_in_reg(6);
+show_in_reg(7);
+
+/* Temps */
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMPEXT_FROM_REG(data->temp[nr],
+						     data->temp_ext[nr]));
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (IS_ADT7468_OFF64(data))
+		val += 64;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (IS_ADT7468_OFF64(data))
+		val += 64;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+		show_temp, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_temp_min, set_temp_min, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_max, set_temp_max, offset - 1);
+
+show_temp_reg(1);
+show_temp_reg(2);
+show_temp_reg(3);
+
+
+/* Automatic PWM control */
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", ZONE_FROM_REG(data->autofan[nr].config));
+}
+
+static ssize_t set_pwm_auto_channels(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->autofan[nr].config = (data->autofan[nr].config & (~0xe0))
+		| ZONE_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+		data->autofan[nr].config);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_auto_pwm_min(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm));
+}
+
+static ssize_t set_pwm_auto_pwm_min(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->autofan[nr].min_pwm = PWM_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr),
+		data->autofan[nr].min_pwm);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm_auto_pwm_minctl(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", data->autofan[nr].min_off);
+}
+
+static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 tmp;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->autofan[nr].min_off = val;
+	tmp = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
+	tmp &= ~(0x20 << nr);
+	if (data->autofan[nr].min_off)
+		tmp |= 0x20 << nr;
+	lm85_write_value(client, LM85_REG_AFAN_SPIKE1, tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define pwm_auto(offset)						\
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels,			\
+		S_IRUGO | S_IWUSR, show_pwm_auto_channels,		\
+		set_pwm_auto_channels, offset - 1);			\
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min,			\
+		S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min,		\
+		set_pwm_auto_pwm_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl,		\
+		S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl,		\
+		set_pwm_auto_pwm_minctl, offset - 1)
+
+pwm_auto(1);
+pwm_auto(2);
+pwm_auto(3);
+
+/* Temperature settings for automatic PWM control */
+
+static ssize_t show_temp_auto_temp_off(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) -
+		HYST_FROM_REG(data->zone[nr].hyst));
+}
+
+static ssize_t set_temp_auto_temp_off(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int min;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	min = TEMP_FROM_REG(data->zone[nr].limit);
+	data->zone[nr].hyst = HYST_TO_REG(min - val);
+	if (nr == 0 || nr == 1) {
+		lm85_write_value(client, LM85_REG_AFAN_HYST1,
+			(data->zone[0].hyst << 4)
+			| data->zone[1].hyst);
+	} else {
+		lm85_write_value(client, LM85_REG_AFAN_HYST2,
+			(data->zone[2].hyst << 4));
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_auto_temp_min(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit));
+}
+
+static ssize_t set_temp_auto_temp_min(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->zone[nr].limit = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
+		data->zone[nr].limit);
+
+/* Update temp_auto_max and temp_auto_range */
+	data->zone[nr].range = RANGE_TO_REG(
+		TEMP_FROM_REG(data->zone[nr].max_desired) -
+		TEMP_FROM_REG(data->zone[nr].limit));
+	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+		((data->zone[nr].range & 0x0f) << 4)
+		| (data->pwm_freq[nr] & 0x07));
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_auto_temp_max(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) +
+		RANGE_FROM_REG(data->zone[nr].range));
+}
+
+static ssize_t set_temp_auto_temp_max(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int min;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	min = TEMP_FROM_REG(data->zone[nr].limit);
+	data->zone[nr].max_desired = TEMP_TO_REG(val);
+	data->zone[nr].range = RANGE_TO_REG(
+		val - min);
+	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+		((data->zone[nr].range & 0x0f) << 4)
+		| (data->pwm_freq[nr] & 0x07));
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_auto_temp_crit(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].critical));
+}
+
+static ssize_t set_temp_auto_temp_crit(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct lm85_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->zone[nr].critical = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
+		data->zone[nr].critical);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_auto(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off,			\
+		S_IRUGO | S_IWUSR, show_temp_auto_temp_off,		\
+		set_temp_auto_temp_off, offset - 1);			\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min,			\
+		S_IRUGO | S_IWUSR, show_temp_auto_temp_min,		\
+		set_temp_auto_temp_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max,			\
+		S_IRUGO | S_IWUSR, show_temp_auto_temp_max,		\
+		set_temp_auto_temp_max, offset - 1);			\
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit,		\
+		S_IRUGO | S_IWUSR, show_temp_auto_temp_crit,		\
+		set_temp_auto_temp_crit, offset - 1);
+
+temp_auto(1);
+temp_auto(2);
+temp_auto(3);
+
+static struct attribute *lm85_attributes[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&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_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_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr,
+
+	&dev_attr_vrm.attr,
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_alarms.attr,
+	NULL
+};
+
+static const struct attribute_group lm85_group = {
+	.attrs = lm85_attributes,
+};
+
+static struct attribute *lm85_attributes_minctl[] = {
+	&sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm85_group_minctl = {
+	.attrs = lm85_attributes_minctl,
+};
+
+static struct attribute *lm85_attributes_temp_off[] = {
+	&sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm85_group_temp_off = {
+	.attrs = lm85_attributes_temp_off,
+};
+
+static struct attribute *lm85_attributes_in4[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm85_group_in4 = {
+	.attrs = lm85_attributes_in4,
+};
+
+static struct attribute *lm85_attributes_in567[] = {
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.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_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm85_group_in567 = {
+	.attrs = lm85_attributes_in567,
+};
+
+static void lm85_init_client(struct i2c_client *client)
+{
+	int value;
+
+	/* Start monitoring if needed */
+	value = lm85_read_value(client, LM85_REG_CONFIG);
+	if (!(value & 0x01)) {
+		dev_info(&client->dev, "Starting monitoring\n");
+		lm85_write_value(client, LM85_REG_CONFIG, value | 0x01);
+	}
+
+	/* Warn about unusual configuration bits */
+	if (value & 0x02)
+		dev_warn(&client->dev, "Device configuration is locked\n");
+	if (!(value & 0x04))
+		dev_warn(&client->dev, "Device is not ready\n");
+}
+
+static int lm85_is_fake(struct i2c_client *client)
+{
+	/*
+	 * Differenciate between real LM96000 and Winbond WPCD377I. The latter
+	 * emulate the former except that it has no hardware monitoring function
+	 * so the readings are always 0.
+	 */
+	int i;
+	u8 in_temp, fan;
+
+	for (i = 0; i < 8; i++) {
+		in_temp = i2c_smbus_read_byte_data(client, 0x20 + i);
+		fan = i2c_smbus_read_byte_data(client, 0x28 + i);
+		if (in_temp != 0x00 || fan != 0xff)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	const char *type_name = NULL;
+	int company, verstep;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		/* We need to be able to do byte I/O */
+		return -ENODEV;
+	}
+
+	/* Determine the chip type */
+	company = lm85_read_value(client, LM85_REG_COMPANY);
+	verstep = lm85_read_value(client, LM85_REG_VERSTEP);
+
+	dev_dbg(&adapter->dev,
+		"Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+		address, company, verstep);
+
+	if (company == LM85_COMPANY_NATIONAL) {
+		switch (verstep) {
+		case LM85_VERSTEP_LM85C:
+			type_name = "lm85c";
+			break;
+		case LM85_VERSTEP_LM85B:
+			type_name = "lm85b";
+			break;
+		case LM85_VERSTEP_LM96000_1:
+		case LM85_VERSTEP_LM96000_2:
+			/* Check for Winbond WPCD377I */
+			if (lm85_is_fake(client)) {
+				dev_dbg(&adapter->dev,
+					"Found Winbond WPCD377I, ignoring\n");
+				return -ENODEV;
+			}
+			type_name = "lm85";
+			break;
+		}
+	} else if (company == LM85_COMPANY_ANALOG_DEV) {
+		switch (verstep) {
+		case LM85_VERSTEP_ADM1027:
+			type_name = "adm1027";
+			break;
+		case LM85_VERSTEP_ADT7463:
+		case LM85_VERSTEP_ADT7463C:
+			type_name = "adt7463";
+			break;
+		case LM85_VERSTEP_ADT7468_1:
+		case LM85_VERSTEP_ADT7468_2:
+			type_name = "adt7468";
+			break;
+		}
+	} else if (company == LM85_COMPANY_SMSC) {
+		switch (verstep) {
+		case LM85_VERSTEP_EMC6D100_A0:
+		case LM85_VERSTEP_EMC6D100_A1:
+			/* Note: we can't tell a '100 from a '101 */
+			type_name = "emc6d100";
+			break;
+		case LM85_VERSTEP_EMC6D102:
+			type_name = "emc6d102";
+			break;
+		case LM85_VERSTEP_EMC6D103_A0:
+		case LM85_VERSTEP_EMC6D103_A1:
+			type_name = "emc6d103";
+			break;
+		case LM85_VERSTEP_EMC6D103S:
+			type_name = "emc6d103s";
+			break;
+		}
+	}
+
+	if (!type_name)
+		return -ENODEV;
+
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct lm85_data *data;
+	int idx = 0;
+
+	data = devm_kzalloc(dev, sizeof(struct lm85_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->type = id->driver_data;
+	mutex_init(&data->update_lock);
+
+	/* Fill in the chip specific driver values */
+	switch (data->type) {
+	case adm1027:
+	case adt7463:
+	case adt7468:
+	case emc6d100:
+	case emc6d102:
+	case emc6d103:
+	case emc6d103s:
+		data->freq_map = adm1027_freq_map;
+		break;
+	default:
+		data->freq_map = lm85_freq_map;
+	}
+
+	/* Set the VRM version */
+	data->vrm = vid_which_vrm();
+
+	/* Initialize the LM85 chip */
+	lm85_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[idx++] = &lm85_group;
+
+	/* minctl and temp_off exist on all chips except emc6d103s */
+	if (data->type != emc6d103s) {
+		data->groups[idx++] = &lm85_group_minctl;
+		data->groups[idx++] = &lm85_group_temp_off;
+	}
+
+	/*
+	 * The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
+	 * as a sixth digital VID input rather than an analog input.
+	 */
+	if (data->type == adt7463 || data->type == adt7468) {
+		u8 vid = lm85_read_value(client, LM85_REG_VID);
+		if (vid & 0x80)
+			data->has_vid5 = true;
+	}
+
+	if (!data->has_vid5)
+		data->groups[idx++] = &lm85_group_in4;
+
+	/* The EMC6D100 has 3 additional voltage inputs */
+	if (data->type == emc6d100)
+		data->groups[idx++] = &lm85_group_in567;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id lm85_id[] = {
+	{ "adm1027", adm1027 },
+	{ "adt7463", adt7463 },
+	{ "adt7468", adt7468 },
+	{ "lm85", lm85 },
+	{ "lm85b", lm85 },
+	{ "lm85c", lm85 },
+	{ "emc6d100", emc6d100 },
+	{ "emc6d101", emc6d100 },
+	{ "emc6d102", emc6d102 },
+	{ "emc6d103", emc6d103 },
+	{ "emc6d103s", emc6d103s },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm85_id);
+
+static struct i2c_driver lm85_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name   = "lm85",
+	},
+	.probe		= lm85_probe,
+	.id_table	= lm85_id,
+	.detect		= lm85_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm85_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
+	"Margit Schubert-While <margitsw@t-online.de>, "
+	"Justin Thiessen <jthiessen@penguincomputing.com>");
+MODULE_DESCRIPTION("LM85-B, LM85-C driver");
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
new file mode 100644
index 0000000..a5e2958
--- /dev/null
+++ b/drivers/hwmon/lm87.c
@@ -0,0 +1,1019 @@
+/*
+ * lm87.c
+ *
+ * Copyright (C) 2000       Frodo Looijaard <frodol@dds.nl>
+ *                          Philip Edelbrock <phil@netroedge.com>
+ *                          Stephen Rousset <stephen.rousset@rocketlogix.com>
+ *                          Dan Eaton <dan.eaton@rocketlogix.com>
+ * Copyright (C) 2004-2008  Jean Delvare <jdelvare@suse.de>
+ *
+ * Original port to Linux 2.6 by Jeff Oliver.
+ *
+ * The LM87 is a sensor chip made by National Semiconductor. It monitors up
+ * to 8 voltages (including its own power source), up to three temperatures
+ * (its own plus up to two external ones) and up to two fans. The default
+ * configuration is 6 voltages, two temperatures and two fans (see below).
+ * Voltages are scaled internally with ratios such that the nominal value of
+ * each voltage correspond to a register value of 192 (which means a
+ * resolution of about 0.5% of the nominal value). Temperature values are
+ * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete
+ * datasheet can be obtained from National's website at:
+ *   http://www.national.com/pf/LM/LM87.html
+ *
+ * Some functions share pins, so not all functions are available at the same
+ * time. Which are depends on the hardware setup. This driver normally
+ * assumes that firmware configured the chip correctly. Where this is not
+ * the case, platform code must set the I2C client's platform_data to point
+ * to a u8 value to be written to the channel register.
+ * For reference, here is the list of exclusive functions:
+ *  - in0+in5 (default) or temp3
+ *  - fan1 (default) or in6
+ *  - fan2 (default) or in7
+ *  - VID lines (default) or IRQ lines (not handled by this driver)
+ *
+ * The LM87 additionally features an analog output, supposedly usable to
+ * control the speed of a fan. All new chips use pulse width modulation
+ * instead. The LM87 is the only hardware monitoring chipset I know of
+ * which uses amplitude modulation. Be careful when using this feature.
+ *
+ * This driver also supports the ADM1024, a sensor chip made by Analog
+ * Devices. That chip is fully compatible with the LM87. Complete
+ * datasheet can be obtained from Analog's website at:
+ *   http://www.analog.com/en/prod/0,2877,ADM1024,00.html
+ *
+ * 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/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e.
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+enum chips { lm87, adm1024 };
+
+/*
+ * The LM87 registers
+ */
+
+/* nr in 0..5 */
+#define LM87_REG_IN(nr)			(0x20 + (nr))
+#define LM87_REG_IN_MAX(nr)		(0x2B + (nr) * 2)
+#define LM87_REG_IN_MIN(nr)		(0x2C + (nr) * 2)
+/* nr in 0..1 */
+#define LM87_REG_AIN(nr)		(0x28 + (nr))
+#define LM87_REG_AIN_MIN(nr)		(0x1A + (nr))
+#define LM87_REG_AIN_MAX(nr)		(0x3B + (nr))
+
+static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 };
+static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B };
+static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
+
+#define LM87_REG_TEMP_HW_INT_LOCK	0x13
+#define LM87_REG_TEMP_HW_EXT_LOCK	0x14
+#define LM87_REG_TEMP_HW_INT		0x17
+#define LM87_REG_TEMP_HW_EXT		0x18
+
+/* nr in 0..1 */
+#define LM87_REG_FAN(nr)		(0x28 + (nr))
+#define LM87_REG_FAN_MIN(nr)		(0x3B + (nr))
+#define LM87_REG_AOUT			0x19
+
+#define LM87_REG_CONFIG			0x40
+#define LM87_REG_CHANNEL_MODE		0x16
+#define LM87_REG_VID_FAN_DIV		0x47
+#define LM87_REG_VID4			0x49
+
+#define LM87_REG_ALARMS1		0x41
+#define LM87_REG_ALARMS2		0x42
+
+#define LM87_REG_COMPANY_ID		0x3E
+#define LM87_REG_REVISION		0x3F
+
+/*
+ * Conversions and various macros
+ * The LM87 uses signed 8-bit values for temperatures.
+ */
+
+#define IN_FROM_REG(reg, scale)	(((reg) * (scale) + 96) / 192)
+#define IN_TO_REG(val, scale)	((val) <= 0 ? 0 : \
+				 (val) * 192 >= (scale) * 255 ? 255 : \
+				 ((val) * 192 + (scale) / 2) / (scale))
+
+#define TEMP_FROM_REG(reg)	((reg) * 1000)
+#define TEMP_TO_REG(val)	((val) <= -127500 ? -128 : \
+				 (val) >= 126500 ? 127 : \
+				 (((val) < 0 ? (val) - 500 : \
+				   (val) + 500) / 1000))
+
+#define FAN_FROM_REG(reg, div)	((reg) == 255 || (reg) == 0 ? 0 : \
+				 (1350000 + (reg)*(div) / 2) / ((reg) * (div)))
+#define FAN_TO_REG(val, div)	((val) * (div) * 255 <= 1350000 ? 255 : \
+				 (1350000 + (val)*(div) / 2) / ((val) * (div)))
+
+#define FAN_DIV_FROM_REG(reg)	(1 << (reg))
+
+/* analog out is 9.80mV/LSB */
+#define AOUT_FROM_REG(reg)	(((reg) * 98 + 5) / 10)
+#define AOUT_TO_REG(val)	((val) <= 0 ? 0 : \
+				 (val) >= 2500 ? 255 : \
+				 ((val) * 10 + 49) / 98)
+
+/* nr in 0..1 */
+#define CHAN_NO_FAN(nr)		(1 << (nr))
+#define CHAN_TEMP3		(1 << 2)
+#define CHAN_VCC_5V		(1 << 3)
+#define CHAN_NO_VID		(1 << 7)
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm87_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* In jiffies */
+
+	u8 channel;		/* register value */
+	u8 config;		/* original register value */
+
+	u8 in[8];		/* register value */
+	u8 in_max[8];		/* register value */
+	u8 in_min[8];		/* register value */
+	u16 in_scale[8];
+
+	s8 temp[3];		/* register value */
+	s8 temp_high[3];	/* register value */
+	s8 temp_low[3];		/* register value */
+	s8 temp_crit_int;	/* min of two register values */
+	s8 temp_crit_ext;	/* min of two register values */
+
+	u8 fan[2];		/* register value */
+	u8 fan_min[2];		/* register value */
+	u8 fan_div[2];		/* register value, shifted right */
+	u8 aout;		/* register value */
+
+	u16 alarms;		/* register values, combined */
+	u8 vid;			/* register values, combined */
+	u8 vrm;
+};
+
+static inline int lm87_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct lm87_data *lm87_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		int i, j;
+
+		dev_dbg(&client->dev, "Updating data.\n");
+
+		i = (data->channel & CHAN_TEMP3) ? 1 : 0;
+		j = (data->channel & CHAN_TEMP3) ? 5 : 6;
+		for (; i < j; i++) {
+			data->in[i] = lm87_read_value(client,
+				      LM87_REG_IN(i));
+			data->in_min[i] = lm87_read_value(client,
+					  LM87_REG_IN_MIN(i));
+			data->in_max[i] = lm87_read_value(client,
+					  LM87_REG_IN_MAX(i));
+		}
+
+		for (i = 0; i < 2; i++) {
+			if (data->channel & CHAN_NO_FAN(i)) {
+				data->in[6+i] = lm87_read_value(client,
+						LM87_REG_AIN(i));
+				data->in_max[6+i] = lm87_read_value(client,
+						    LM87_REG_AIN_MAX(i));
+				data->in_min[6+i] = lm87_read_value(client,
+						    LM87_REG_AIN_MIN(i));
+
+			} else {
+				data->fan[i] = lm87_read_value(client,
+					       LM87_REG_FAN(i));
+				data->fan_min[i] = lm87_read_value(client,
+						   LM87_REG_FAN_MIN(i));
+			}
+		}
+
+		j = (data->channel & CHAN_TEMP3) ? 3 : 2;
+		for (i = 0 ; i < j; i++) {
+			data->temp[i] = lm87_read_value(client,
+					LM87_REG_TEMP[i]);
+			data->temp_high[i] = lm87_read_value(client,
+					     LM87_REG_TEMP_HIGH[i]);
+			data->temp_low[i] = lm87_read_value(client,
+					    LM87_REG_TEMP_LOW[i]);
+		}
+
+		i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK);
+		j = lm87_read_value(client, LM87_REG_TEMP_HW_INT);
+		data->temp_crit_int = min(i, j);
+
+		i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK);
+		j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT);
+		data->temp_crit_ext = min(i, j);
+
+		i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = (i >> 6) & 0x03;
+		data->vid = (i & 0x0F)
+			  | (lm87_read_value(client, LM87_REG_VID4) & 0x01)
+			     << 4;
+
+		data->alarms = lm87_read_value(client, LM87_REG_ALARMS1)
+			     | (lm87_read_value(client, LM87_REG_ALARMS2)
+				<< 8);
+		data->aout = lm87_read_value(client, LM87_REG_AOUT);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[nr],
+		       data->in_scale[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[nr],
+		       data->in_scale[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[nr],
+		       data->in_scale[nr]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
+	lm87_write_value(client, nr < 6 ? LM87_REG_IN_MIN(nr) :
+			 LM87_REG_AIN_MIN(nr - 6), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev,  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
+	lm87_write_value(client, nr < 6 ? LM87_REG_IN_MAX(nr) :
+			 LM87_REG_AIN_MAX(nr - 6), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define set_in(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+		show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+		show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+		show_in_max, set_in_max, offset)
+set_in(0);
+set_in(1);
+set_in(2);
+set_in(3);
+set_in(4);
+set_in(5);
+set_in(6);
+set_in(7);
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_low(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n",
+		       TEMP_FROM_REG(data->temp_low[nr]));
+}
+
+static ssize_t show_temp_high(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n",
+		       TEMP_FROM_REG(data->temp_high[nr]));
+}
+
+static ssize_t set_temp_low(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_low[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_high(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_high[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define set_temp(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+		show_temp_input, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+		show_temp_high, set_temp_high, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+		show_temp_low, set_temp_low, offset - 1)
+set_temp(1);
+set_temp(2);
+set_temp(3);
+
+static ssize_t show_temp_crit_int(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int));
+}
+
+static ssize_t show_temp_crit_ext(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext));
+}
+
+static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL);
+static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL);
+static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL);
+
+static ssize_t show_fan_input(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		       FAN_DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+		       FAN_DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n",
+		       FAN_DIV_FROM_REG(data->fan_div[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val,
+			    FAN_DIV_FROM_REG(data->fan_div[nr]));
+	lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan clock divider.  This follows the principle
+ * of least surprise; the user doesn't expect the fan minimum to change just
+ * because the divider changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	int nr = to_sensor_dev_attr(attr)->index;
+	long val;
+	int err;
+	unsigned long min;
+	u8 reg;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   FAN_DIV_FROM_REG(data->fan_div[nr]));
+
+	switch (val) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+	switch (nr) {
+	case 0:
+	    reg = (reg & 0xCF) | (data->fan_div[0] << 4);
+	    break;
+	case 1:
+	    reg = (reg & 0x3F) | (data->fan_div[1] << 6);
+	    break;
+	}
+	lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg);
+
+	data->fan_min[nr] = FAN_TO_REG(min, val);
+	lm87_write_value(client, LM87_REG_FAN_MIN(nr),
+			 data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define set_fan(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+		show_fan_input, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+		show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+		show_fan_div, set_fan_div, offset - 1)
+set_fan(1);
+set_fan(2);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct lm87_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct lm87_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_aout(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+}
+static ssize_t set_aout(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->aout = AOUT_TO_REG(val);
+	lm87_write_value(client, LM87_REG_AOUT, data->aout);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct lm87_data *data = lm87_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+
+/*
+ * Real code
+ */
+
+static struct attribute *lm87_attributes[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&dev_attr_temp1_crit.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&dev_attr_temp2_crit.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&dev_attr_aout_output.attr,
+
+	NULL
+};
+
+static const struct attribute_group lm87_group = {
+	.attrs = lm87_attributes,
+};
+
+static struct attribute *lm87_attributes_in6[] = {
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_in6 = {
+	.attrs = lm87_attributes_in6,
+};
+
+static struct attribute *lm87_attributes_fan1[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_fan1 = {
+	.attrs = lm87_attributes_fan1,
+};
+
+static struct attribute *lm87_attributes_in7[] = {
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_in7 = {
+	.attrs = lm87_attributes_in7,
+};
+
+static struct attribute *lm87_attributes_fan2[] = {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_fan2 = {
+	.attrs = lm87_attributes_fan2,
+};
+
+static struct attribute *lm87_attributes_temp3[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&dev_attr_temp3_crit.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_temp3 = {
+	.attrs = lm87_attributes_temp3,
+};
+
+static struct attribute *lm87_attributes_in0_5[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_in0_5 = {
+	.attrs = lm87_attributes_in0_5,
+};
+
+static struct attribute *lm87_attributes_vid[] = {
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	NULL
+};
+
+static const struct attribute_group lm87_group_vid = {
+	.attrs = lm87_attributes_vid,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm87_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	const char *name;
+	u8 cid, rev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	if (lm87_read_value(client, LM87_REG_CONFIG) & 0x80)
+		return -ENODEV;
+
+	/* Now, we do the remaining detection. */
+	cid = lm87_read_value(client, LM87_REG_COMPANY_ID);
+	rev = lm87_read_value(client, LM87_REG_REVISION);
+
+	if (cid == 0x02			/* National Semiconductor */
+	 && (rev >= 0x01 && rev <= 0x08))
+		name = "lm87";
+	else if (cid == 0x41		/* Analog Devices */
+	      && (rev & 0xf0) == 0x10)
+		name = "adm1024";
+	else {
+		dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void lm87_remove_files(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+
+	sysfs_remove_group(&dev->kobj, &lm87_group);
+	sysfs_remove_group(&dev->kobj, &lm87_group_in6);
+	sysfs_remove_group(&dev->kobj, &lm87_group_fan1);
+	sysfs_remove_group(&dev->kobj, &lm87_group_in7);
+	sysfs_remove_group(&dev->kobj, &lm87_group_fan2);
+	sysfs_remove_group(&dev->kobj, &lm87_group_temp3);
+	sysfs_remove_group(&dev->kobj, &lm87_group_in0_5);
+	sysfs_remove_group(&dev->kobj, &lm87_group_vid);
+}
+
+static void lm87_init_client(struct i2c_client *client)
+{
+	struct lm87_data *data = i2c_get_clientdata(client);
+
+	if (dev_get_platdata(&client->dev)) {
+		data->channel = *(u8 *)dev_get_platdata(&client->dev);
+		lm87_write_value(client,
+				 LM87_REG_CHANNEL_MODE, data->channel);
+	} else {
+		data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
+	}
+	data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F;
+
+	if (!(data->config & 0x01)) {
+		int i;
+
+		/* Limits are left uninitialized after power-up */
+		for (i = 1; i < 6; i++) {
+			lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00);
+			lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF);
+		}
+		for (i = 0; i < 2; i++) {
+			lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F);
+			lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00);
+			lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00);
+			lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF);
+		}
+		if (data->channel & CHAN_TEMP3) {
+			lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F);
+			lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00);
+		} else {
+			lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00);
+			lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF);
+		}
+	}
+
+	/* Make sure Start is set and INT#_Clear is clear */
+	if ((data->config & 0x09) != 0x01)
+		lm87_write_value(client, LM87_REG_CONFIG,
+				 (data->config & 0x77) | 0x01);
+}
+
+static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct lm87_data *data;
+	int err;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct lm87_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM87 chip */
+	lm87_init_client(client);
+
+	data->in_scale[0] = 2500;
+	data->in_scale[1] = 2700;
+	data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300;
+	data->in_scale[3] = 5000;
+	data->in_scale[4] = 12000;
+	data->in_scale[5] = 2700;
+	data->in_scale[6] = 1875;
+	data->in_scale[7] = 1875;
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &lm87_group);
+	if (err)
+		goto exit_stop;
+
+	if (data->channel & CHAN_NO_FAN(0)) {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_in6);
+		if (err)
+			goto exit_remove;
+	} else {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan1);
+		if (err)
+			goto exit_remove;
+	}
+
+	if (data->channel & CHAN_NO_FAN(1)) {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_in7);
+		if (err)
+			goto exit_remove;
+	} else {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan2);
+		if (err)
+			goto exit_remove;
+	}
+
+	if (data->channel & CHAN_TEMP3) {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_temp3);
+		if (err)
+			goto exit_remove;
+	} else {
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_in0_5);
+		if (err)
+			goto exit_remove;
+	}
+
+	if (!(data->channel & CHAN_NO_VID)) {
+		data->vrm = vid_which_vrm();
+		err = sysfs_create_group(&client->dev.kobj, &lm87_group_vid);
+		if (err)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	lm87_remove_files(client);
+exit_stop:
+	lm87_write_value(client, LM87_REG_CONFIG, data->config);
+	return err;
+}
+
+static int lm87_remove(struct i2c_client *client)
+{
+	struct lm87_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	lm87_remove_files(client);
+
+	lm87_write_value(client, LM87_REG_CONFIG, data->config);
+	return 0;
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id lm87_id[] = {
+	{ "lm87", lm87 },
+	{ "adm1024", adm1024 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm87_id);
+
+static struct i2c_driver lm87_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm87",
+	},
+	.probe		= lm87_probe,
+	.remove		= lm87_remove,
+	.id_table	= lm87_id,
+	.detect		= lm87_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm87_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de> and others");
+MODULE_DESCRIPTION("LM87 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
new file mode 100644
index 0000000..c9ff08d
--- /dev/null
+++ b/drivers/hwmon/lm90.c
@@ -0,0 +1,1669 @@
+/*
+ * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
+ *          monitoring
+ * Copyright (C) 2003-2010  Jean Delvare <jdelvare@suse.de>
+ *
+ * Based on the lm83 driver. The LM90 is a sensor chip made by National
+ * Semiconductor. It reports up to two temperatures (its own plus up to
+ * one external one) with a 0.125 deg resolution (1 deg for local
+ * temperature) and a 3-4 deg accuracy.
+ *
+ * This driver also supports the LM89 and LM99, two other sensor chips
+ * made by National Semiconductor. Both have an increased remote
+ * temperature measurement accuracy (1 degree), and the LM99
+ * additionally shifts remote temperatures (measured and limits) by 16
+ * degrees, which allows for higher temperatures measurement.
+ * Note that there is no way to differentiate between both chips.
+ * When device is auto-detected, the driver will assume an LM99.
+ *
+ * This driver also supports the LM86, another sensor chip made by
+ * National Semiconductor. It is exactly similar to the LM90 except it
+ * has a higher accuracy.
+ *
+ * This driver also supports the ADM1032, a sensor chip made by Analog
+ * Devices. That chip is similar to the LM90, with a few differences
+ * that are not handled by this driver. Among others, it has a higher
+ * accuracy than the LM90, much like the LM86 does.
+ *
+ * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor
+ * chips made by Maxim. These chips are similar to the LM86.
+ * Note that there is no easy way to differentiate between the three
+ * variants. We use the device address to detect MAX6659, which will result
+ * in a detection as max6657 if it is on address 0x4c. The extra address
+ * and features of the MAX6659 are only supported if the chip is configured
+ * explicitly as max6659, or if its address is not 0x4c.
+ * These chips lack the remote temperature offset feature.
+ *
+ * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
+ * MAX6692 chips made by Maxim.  These are again similar to the LM86,
+ * but they use unsigned temperature values and can report temperatures
+ * from 0 to 145 degrees.
+ *
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. The MAX6680 and MAX6681 only differ in the pinout so they can
+ * be treated identically.
+ *
+ * This driver also supports the MAX6695 and MAX6696, two other sensor
+ * chips made by Maxim. These are also quite similar to other Maxim
+ * chips, but support three temperature sensors instead of two. MAX6695
+ * and MAX6696 only differ in the pinout so they can be treated identically.
+ *
+ * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as
+ * NCT1008 from ON Semiconductor. The chips are supported in both compatibility
+ * and extended mode. They are mostly compatible with LM90 except for a data
+ * format difference for the temperature value registers.
+ *
+ * This driver also supports the SA56004 from Philips. This device is
+ * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
+ *
+ * This driver also supports the G781 from GMT. This device is compatible
+ * with the ADM1032.
+ *
+ * This driver also supports TMP451 from Texas Instruments. This device is
+ * supported in both compatibility and extended mode. It's mostly compatible
+ * with ADT7461 except for local temperature low byte register and max
+ * conversion rate.
+ *
+ * Since the LM90 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * 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-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+
+/*
+ * Addresses to scan
+ * Address is fully defined internally and cannot be changed except for
+ * MAX6659, MAX6680 and MAX6681.
+ * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649,
+ * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c.
+ * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D
+ * have address 0x4d.
+ * MAX6647 has address 0x4e.
+ * MAX6659 can have address 0x4c, 0x4d or 0x4e.
+ * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ * 0x4c, 0x4d or 0x4e.
+ * SA56004 can have address 0x48 through 0x4F.
+ */
+
+static const unsigned short normal_i2c[] = {
+	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+	0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+
+enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
+	max6646, w83l771, max6696, sa56004, g781, tmp451 };
+
+/*
+ * The LM90 registers
+ */
+
+#define LM90_REG_R_MAN_ID		0xFE
+#define LM90_REG_R_CHIP_ID		0xFF
+#define LM90_REG_R_CONFIG1		0x03
+#define LM90_REG_W_CONFIG1		0x09
+#define LM90_REG_R_CONFIG2		0xBF
+#define LM90_REG_W_CONFIG2		0xBF
+#define LM90_REG_R_CONVRATE		0x04
+#define LM90_REG_W_CONVRATE		0x0A
+#define LM90_REG_R_STATUS		0x02
+#define LM90_REG_R_LOCAL_TEMP		0x00
+#define LM90_REG_R_LOCAL_HIGH		0x05
+#define LM90_REG_W_LOCAL_HIGH		0x0B
+#define LM90_REG_R_LOCAL_LOW		0x06
+#define LM90_REG_W_LOCAL_LOW		0x0C
+#define LM90_REG_R_LOCAL_CRIT		0x20
+#define LM90_REG_W_LOCAL_CRIT		0x20
+#define LM90_REG_R_REMOTE_TEMPH		0x01
+#define LM90_REG_R_REMOTE_TEMPL		0x10
+#define LM90_REG_R_REMOTE_OFFSH		0x11
+#define LM90_REG_W_REMOTE_OFFSH		0x11
+#define LM90_REG_R_REMOTE_OFFSL		0x12
+#define LM90_REG_W_REMOTE_OFFSL		0x12
+#define LM90_REG_R_REMOTE_HIGHH		0x07
+#define LM90_REG_W_REMOTE_HIGHH		0x0D
+#define LM90_REG_R_REMOTE_HIGHL		0x13
+#define LM90_REG_W_REMOTE_HIGHL		0x13
+#define LM90_REG_R_REMOTE_LOWH		0x08
+#define LM90_REG_W_REMOTE_LOWH		0x0E
+#define LM90_REG_R_REMOTE_LOWL		0x14
+#define LM90_REG_W_REMOTE_LOWL		0x14
+#define LM90_REG_R_REMOTE_CRIT		0x19
+#define LM90_REG_W_REMOTE_CRIT		0x19
+#define LM90_REG_R_TCRIT_HYST		0x21
+#define LM90_REG_W_TCRIT_HYST		0x21
+
+/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */
+
+#define MAX6657_REG_R_LOCAL_TEMPL	0x11
+#define MAX6696_REG_R_STATUS2		0x12
+#define MAX6659_REG_R_REMOTE_EMERG	0x16
+#define MAX6659_REG_W_REMOTE_EMERG	0x16
+#define MAX6659_REG_R_LOCAL_EMERG	0x17
+#define MAX6659_REG_W_LOCAL_EMERG	0x17
+
+/*  SA56004 registers */
+
+#define SA56004_REG_R_LOCAL_TEMPL 0x22
+
+#define LM90_DEF_CONVRATE_RVAL	6	/* Def conversion rate register value */
+#define LM90_MAX_CONVRATE_MS	16000	/* Maximum conversion rate in ms */
+
+/* TMP451 registers */
+#define TMP451_REG_R_LOCAL_TEMPL	0x15
+
+/*
+ * Device flags
+ */
+#define LM90_FLAG_ADT7461_EXT	(1 << 0) /* ADT7461 extended mode	*/
+/* Device features */
+#define LM90_HAVE_OFFSET	(1 << 1) /* temperature offset register	*/
+#define LM90_HAVE_REM_LIMIT_EXT	(1 << 3) /* extended remote limit	*/
+#define LM90_HAVE_EMERGENCY	(1 << 4) /* 3rd upper (emergency) limit	*/
+#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
+#define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
+#define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
+
+/* LM90 status */
+#define LM90_STATUS_LTHRM	(1 << 0) /* local THERM limit tripped */
+#define LM90_STATUS_RTHRM	(1 << 1) /* remote THERM limit tripped */
+#define LM90_STATUS_ROPEN	(1 << 2) /* remote is an open circuit */
+#define LM90_STATUS_RLOW	(1 << 3) /* remote low temp limit tripped */
+#define LM90_STATUS_RHIGH	(1 << 4) /* remote high temp limit tripped */
+#define LM90_STATUS_LLOW	(1 << 5) /* local low temp limit tripped */
+#define LM90_STATUS_LHIGH	(1 << 6) /* local high temp limit tripped */
+
+#define MAX6696_STATUS2_R2THRM	(1 << 1) /* remote2 THERM limit tripped */
+#define MAX6696_STATUS2_R2OPEN	(1 << 2) /* remote2 is an open circuit */
+#define MAX6696_STATUS2_R2LOW	(1 << 3) /* remote2 low temp limit tripped */
+#define MAX6696_STATUS2_R2HIGH	(1 << 4) /* remote2 high temp limit tripped */
+#define MAX6696_STATUS2_ROT2	(1 << 5) /* remote emergency limit tripped */
+#define MAX6696_STATUS2_R2OT2	(1 << 6) /* remote2 emergency limit tripped */
+#define MAX6696_STATUS2_LOT2	(1 << 7) /* local emergency limit tripped */
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id lm90_id[] = {
+	{ "adm1032", adm1032 },
+	{ "adt7461", adt7461 },
+	{ "adt7461a", adt7461 },
+	{ "g781", g781 },
+	{ "lm90", lm90 },
+	{ "lm86", lm86 },
+	{ "lm89", lm86 },
+	{ "lm99", lm99 },
+	{ "max6646", max6646 },
+	{ "max6647", max6646 },
+	{ "max6649", max6646 },
+	{ "max6657", max6657 },
+	{ "max6658", max6657 },
+	{ "max6659", max6659 },
+	{ "max6680", max6680 },
+	{ "max6681", max6680 },
+	{ "max6695", max6696 },
+	{ "max6696", max6696 },
+	{ "nct1008", adt7461 },
+	{ "w83l771", w83l771 },
+	{ "sa56004", sa56004 },
+	{ "tmp451", tmp451 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm90_id);
+
+/*
+ * chip type specific parameters
+ */
+struct lm90_params {
+	u32 flags;		/* Capabilities */
+	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
+				/* Upper 8 bits for max6695/96 */
+	u8 max_convrate;	/* Maximum conversion rate register value */
+	u8 reg_local_ext;	/* Extended local temp register (optional) */
+};
+
+static const struct lm90_params lm90_params[] = {
+	[adm1032] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 10,
+	},
+	[adt7461] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 10,
+	},
+	[g781] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+	},
+	[lm86] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[lm90] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[lm99] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[max6646] = {
+		.alert_alarms = 0x7c,
+		.max_convrate = 6,
+		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+	},
+	[max6657] = {
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+	},
+	[max6659] = {
+		.flags = LM90_HAVE_EMERGENCY,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+	},
+	[max6680] = {
+		.flags = LM90_HAVE_OFFSET,
+		.alert_alarms = 0x7c,
+		.max_convrate = 7,
+	},
+	[max6696] = {
+		.flags = LM90_HAVE_EMERGENCY
+		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
+		.alert_alarms = 0x1c7c,
+		.max_convrate = 6,
+		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+	},
+	[w83l771] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+	},
+	[sa56004] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+		.reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
+	},
+	[tmp451] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 9,
+		.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
+	}
+};
+
+/*
+ * TEMP8 register index
+ */
+enum lm90_temp8_reg_index {
+	LOCAL_LOW = 0,
+	LOCAL_HIGH,
+	LOCAL_CRIT,
+	REMOTE_CRIT,
+	LOCAL_EMERG,	/* max6659 and max6695/96 */
+	REMOTE_EMERG,	/* max6659 and max6695/96 */
+	REMOTE2_CRIT,	/* max6695/96 only */
+	REMOTE2_EMERG,	/* max6695/96 only */
+	TEMP8_REG_NUM
+};
+
+/*
+ * TEMP11 register index
+ */
+enum lm90_temp11_reg_index {
+	REMOTE_TEMP = 0,
+	REMOTE_LOW,
+	REMOTE_HIGH,
+	REMOTE_OFFSET,	/* except max6646, max6657/58/59, and max6695/96 */
+	LOCAL_TEMP,
+	REMOTE2_TEMP,	/* max6695/96 only */
+	REMOTE2_LOW,	/* max6695/96 only */
+	REMOTE2_HIGH,	/* max6695/96 only */
+	TEMP11_REG_NUM
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm90_data {
+	struct i2c_client *client;
+	struct device *hwmon_dev;
+	const struct attribute_group *groups[6];
+	struct mutex update_lock;
+	struct regulator *regulator;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+	int kind;
+	u32 flags;
+
+	int update_interval;	/* in milliseconds */
+
+	u8 config_orig;		/* Original configuration register value */
+	u8 convrate_orig;	/* Original conversion rate register value */
+	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
+				/* Upper 8 bits for max6695/96 */
+	u8 max_convrate;	/* Maximum conversion rate */
+	u8 reg_local_ext;	/* local extension register offset */
+
+	/* registers values */
+	s8 temp8[TEMP8_REG_NUM];
+	s16 temp11[TEMP11_REG_NUM];
+	u8 temp_hyst;
+	u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
+};
+
+/*
+ * Support functions
+ */
+
+/*
+ * The ADM1032 supports PEC but not on write byte transactions, so we need
+ * to explicitly ask for a transaction without PEC.
+ */
+static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
+{
+	return i2c_smbus_xfer(client->adapter, client->addr,
+			      client->flags & ~I2C_CLIENT_PEC,
+			      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+
+/*
+ * It is assumed that client->update_lock is held (unless we are in
+ * detection or initialization steps). This matters when PEC is enabled,
+ * because we don't want the address pointer to change between the write
+ * byte and the read byte transactions.
+ */
+static int lm90_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+{
+	int err;
+
+	if (client->flags & I2C_CLIENT_PEC) {
+		err = adm1032_write_byte(client, reg);
+		if (err >= 0)
+			err = i2c_smbus_read_byte(client);
+	} else
+		err = i2c_smbus_read_byte_data(client, reg);
+
+	if (err < 0) {
+		dev_warn(&client->dev, "Register %#02x read failed (%d)\n",
+			 reg, err);
+		return err;
+	}
+	*value = err;
+
+	return 0;
+}
+
+static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
+{
+	int err;
+	u8 oldh, newh, l;
+
+	/*
+	 * There is a trick here. We have to read two registers to have the
+	 * sensor temperature, but we have to beware a conversion could occur
+	 * between the readings. The datasheet says we should either use
+	 * the one-shot conversion register, which we don't want to do
+	 * (disables hardware monitoring) or monitor the busy bit, which is
+	 * impossible (we can't read the values and monitor that bit at the
+	 * exact same time). So the solution used here is to read the high
+	 * byte once, then the low byte, then the high byte again. If the new
+	 * high byte matches the old one, then we have a valid reading. Else
+	 * we have to read the low byte again, and now we believe we have a
+	 * correct reading.
+	 */
+	if ((err = lm90_read_reg(client, regh, &oldh))
+	 || (err = lm90_read_reg(client, regl, &l))
+	 || (err = lm90_read_reg(client, regh, &newh)))
+		return err;
+	if (oldh != newh) {
+		err = lm90_read_reg(client, regl, &l);
+		if (err)
+			return err;
+	}
+	*value = (newh << 8) | l;
+
+	return 0;
+}
+
+/*
+ * client->update_lock must be held when calling this function (unless we are
+ * in detection or initialization steps), and while a remote channel other
+ * than channel 0 is selected. Also, calling code must make sure to re-select
+ * external channel 0 before releasing the lock. This is necessary because
+ * various registers have different meanings as a result of selecting a
+ * non-default remote channel.
+ */
+static inline void lm90_select_remote_channel(struct i2c_client *client,
+					      struct lm90_data *data,
+					      int channel)
+{
+	u8 config;
+
+	if (data->kind == max6696) {
+		lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+		config &= ~0x08;
+		if (channel)
+			config |= 0x08;
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+					  config);
+	}
+}
+
+/*
+ * Set conversion rate.
+ * client->update_lock must be held when calling this function (unless we are
+ * in detection or initialization steps).
+ */
+static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
+			      unsigned int interval)
+{
+	int i;
+	unsigned int update_interval;
+
+	/* Shift calculations to avoid rounding errors */
+	interval <<= 6;
+
+	/* find the nearest update rate */
+	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
+	     i < data->max_convrate; i++, update_interval >>= 1)
+		if (interval >= update_interval * 3 / 4)
+			break;
+
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
+	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
+}
+
+static struct lm90_data *lm90_update_device(struct device *dev)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long next_update;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated +
+		      msecs_to_jiffies(data->update_interval);
+	if (time_after(jiffies, next_update) || !data->valid) {
+		u8 h, l;
+		u8 alarms;
+
+		dev_dbg(&client->dev, "Updating lm90 data.\n");
+		lm90_read_reg(client, LM90_REG_R_LOCAL_LOW,
+			      &data->temp8[LOCAL_LOW]);
+		lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH,
+			      &data->temp8[LOCAL_HIGH]);
+		lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT,
+			      &data->temp8[LOCAL_CRIT]);
+		lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT,
+			      &data->temp8[REMOTE_CRIT]);
+		lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
+
+		if (data->reg_local_ext) {
+			lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
+				    data->reg_local_ext,
+				    &data->temp11[LOCAL_TEMP]);
+		} else {
+			if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
+					  &h) == 0)
+				data->temp11[LOCAL_TEMP] = h << 8;
+		}
+		lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
+			    LM90_REG_R_REMOTE_TEMPL,
+			    &data->temp11[REMOTE_TEMP]);
+
+		if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) {
+			data->temp11[REMOTE_LOW] = h << 8;
+			if ((data->flags & LM90_HAVE_REM_LIMIT_EXT)
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL,
+					  &l) == 0)
+				data->temp11[REMOTE_LOW] |= l;
+		}
+		if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) {
+			data->temp11[REMOTE_HIGH] = h << 8;
+			if ((data->flags & LM90_HAVE_REM_LIMIT_EXT)
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL,
+					  &l) == 0)
+				data->temp11[REMOTE_HIGH] |= l;
+		}
+
+		if (data->flags & LM90_HAVE_OFFSET) {
+			if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+					  &h) == 0
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+					  &l) == 0)
+				data->temp11[REMOTE_OFFSET] = (h << 8) | l;
+		}
+		if (data->flags & LM90_HAVE_EMERGENCY) {
+			lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG,
+				      &data->temp8[LOCAL_EMERG]);
+			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
+				      &data->temp8[REMOTE_EMERG]);
+		}
+		lm90_read_reg(client, LM90_REG_R_STATUS, &alarms);
+		data->alarms = alarms;	/* save as 16 bit value */
+
+		if (data->kind == max6696) {
+			lm90_select_remote_channel(client, data, 1);
+			lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT,
+				      &data->temp8[REMOTE2_CRIT]);
+			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
+				      &data->temp8[REMOTE2_EMERG]);
+			lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
+				    LM90_REG_R_REMOTE_TEMPL,
+				    &data->temp11[REMOTE2_TEMP]);
+			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h))
+				data->temp11[REMOTE2_LOW] = h << 8;
+			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h))
+				data->temp11[REMOTE2_HIGH] = h << 8;
+			lm90_select_remote_channel(client, data, 0);
+
+			if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2,
+					   &alarms))
+				data->alarms |= alarms << 8;
+		}
+
+		/*
+		 * Re-enable ALERT# output if it was originally enabled and
+		 * relevant alarms are all clear
+		 */
+		if ((data->config_orig & 0x80) == 0
+		 && (data->alarms & data->alert_alarms) == 0) {
+			u8 config;
+
+			lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+			if (config & 0x80) {
+				dev_dbg(&client->dev, "Re-enabling ALERT#\n");
+				i2c_smbus_write_byte_data(client,
+							  LM90_REG_W_CONFIG1,
+							  config & ~0x80);
+			}
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Conversions
+ * For local temperatures and limits, critical limits and the hysteresis
+ * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
+ * For remote temperatures and limits, it uses signed 11-bit values with
+ * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.  Some
+ * Maxim chips use unsigned values.
+ */
+
+static inline int temp_from_s8(s8 val)
+{
+	return val * 1000;
+}
+
+static inline int temp_from_u8(u8 val)
+{
+	return val * 1000;
+}
+
+static inline int temp_from_s16(s16 val)
+{
+	return val / 32 * 125;
+}
+
+static inline int temp_from_u16(u16 val)
+{
+	return val / 32 * 125;
+}
+
+static s8 temp_to_s8(long val)
+{
+	if (val <= -128000)
+		return -128;
+	if (val >= 127000)
+		return 127;
+	if (val < 0)
+		return (val - 500) / 1000;
+	return (val + 500) / 1000;
+}
+
+static u8 temp_to_u8(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 255000)
+		return 255;
+	return (val + 500) / 1000;
+}
+
+static s16 temp_to_s16(long val)
+{
+	if (val <= -128000)
+		return 0x8000;
+	if (val >= 127875)
+		return 0x7FE0;
+	if (val < 0)
+		return (val - 62) / 125 * 32;
+	return (val + 62) / 125 * 32;
+}
+
+static u8 hyst_to_reg(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 30500)
+		return 31;
+	return (val + 500) / 1000;
+}
+
+/*
+ * ADT7461 in compatibility mode is almost identical to LM90 except that
+ * attempts to write values that are outside the range 0 < temp < 127 are
+ * treated as the boundary value.
+ *
+ * ADT7461 in "extended mode" operation uses unsigned integers offset by
+ * 64 (e.g., 0 -> -64 degC).  The range is restricted to -64..191 degC.
+ */
+static inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val)
+{
+	if (data->flags & LM90_FLAG_ADT7461_EXT)
+		return (val - 64) * 1000;
+	else
+		return temp_from_s8(val);
+}
+
+static inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val)
+{
+	if (data->flags & LM90_FLAG_ADT7461_EXT)
+		return (val - 0x4000) / 64 * 250;
+	else
+		return temp_from_s16(val);
+}
+
+static u8 temp_to_u8_adt7461(struct lm90_data *data, long val)
+{
+	if (data->flags & LM90_FLAG_ADT7461_EXT) {
+		if (val <= -64000)
+			return 0;
+		if (val >= 191000)
+			return 0xFF;
+		return (val + 500 + 64000) / 1000;
+	} else {
+		if (val <= 0)
+			return 0;
+		if (val >= 127000)
+			return 127;
+		return (val + 500) / 1000;
+	}
+}
+
+static u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
+{
+	if (data->flags & LM90_FLAG_ADT7461_EXT) {
+		if (val <= -64000)
+			return 0;
+		if (val >= 191750)
+			return 0xFFC0;
+		return (val + 64000 + 125) / 250 * 64;
+	} else {
+		if (val <= 0)
+			return 0;
+		if (val >= 127750)
+			return 0x7FC0;
+		return (val + 125) / 250 * 64;
+	}
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = lm90_update_device(dev);
+	int temp;
+
+	if (data->kind == adt7461 || data->kind == tmp451)
+		temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+	else if (data->kind == max6646)
+		temp = temp_from_u8(data->temp8[attr->index]);
+	else
+		temp = temp_from_s8(data->temp8[attr->index]);
+
+	/* +16 degrees offset for temp2 for the LM99 */
+	if (data->kind == lm99 && attr->index == 3)
+		temp += 16000;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	static const u8 reg[TEMP8_REG_NUM] = {
+		LM90_REG_W_LOCAL_LOW,
+		LM90_REG_W_LOCAL_HIGH,
+		LM90_REG_W_LOCAL_CRIT,
+		LM90_REG_W_REMOTE_CRIT,
+		MAX6659_REG_W_LOCAL_EMERG,
+		MAX6659_REG_W_REMOTE_EMERG,
+		LM90_REG_W_REMOTE_CRIT,
+		MAX6659_REG_W_REMOTE_EMERG,
+	};
+
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* +16 degrees offset for temp2 for the LM99 */
+	if (data->kind == lm99 && attr->index == 3)
+		val -= 16000;
+
+	mutex_lock(&data->update_lock);
+	if (data->kind == adt7461 || data->kind == tmp451)
+		data->temp8[nr] = temp_to_u8_adt7461(data, val);
+	else if (data->kind == max6646)
+		data->temp8[nr] = temp_to_u8(val);
+	else
+		data->temp8[nr] = temp_to_s8(val);
+
+	lm90_select_remote_channel(client, data, nr >= 6);
+	i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
+	lm90_select_remote_channel(client, data, 0);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
+			   char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct lm90_data *data = lm90_update_device(dev);
+	int temp;
+
+	if (data->kind == adt7461 || data->kind == tmp451)
+		temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
+	else if (data->kind == max6646)
+		temp = temp_from_u16(data->temp11[attr->index]);
+	else
+		temp = temp_from_s16(data->temp11[attr->index]);
+
+	/* +16 degrees offset for temp2 for the LM99 */
+	if (data->kind == lm99 &&  attr->index <= 2)
+		temp += 16000;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	struct {
+		u8 high;
+		u8 low;
+		int channel;
+	} reg[5] = {
+		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 0 },
+		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 0 },
+		{ LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL, 0 },
+		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 1 },
+		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 1 }
+	};
+
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->nr;
+	int index = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* +16 degrees offset for temp2 for the LM99 */
+	if (data->kind == lm99 && index <= 2)
+		val -= 16000;
+
+	mutex_lock(&data->update_lock);
+	if (data->kind == adt7461 || data->kind == tmp451)
+		data->temp11[index] = temp_to_u16_adt7461(data, val);
+	else if (data->kind == max6646)
+		data->temp11[index] = temp_to_u8(val) << 8;
+	else if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+		data->temp11[index] = temp_to_s16(val);
+	else
+		data->temp11[index] = temp_to_s8(val) << 8;
+
+	lm90_select_remote_channel(client, data, reg[nr].channel);
+	i2c_smbus_write_byte_data(client, reg[nr].high,
+				  data->temp11[index] >> 8);
+	if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+		i2c_smbus_write_byte_data(client, reg[nr].low,
+					  data->temp11[index] & 0xff);
+	lm90_select_remote_channel(client, data, 0);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temphyst(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = lm90_update_device(dev);
+	int temp;
+
+	if (data->kind == adt7461 || data->kind == tmp451)
+		temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+	else if (data->kind == max6646)
+		temp = temp_from_u8(data->temp8[attr->index]);
+	else
+		temp = temp_from_s8(data->temp8[attr->index]);
+
+	/* +16 degrees offset for temp2 for the LM99 */
+	if (data->kind == lm99 && attr->index == 3)
+		temp += 16000;
+
+	return sprintf(buf, "%d\n", temp - temp_from_s8(data->temp_hyst));
+}
+
+static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
+			    const char *buf, size_t count)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+	int temp;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (data->kind == adt7461 || data->kind == tmp451)
+		temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
+	else if (data->kind == max6646)
+		temp = temp_from_u8(data->temp8[LOCAL_CRIT]);
+	else
+		temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
+
+	data->temp_hyst = hyst_to_reg(temp - val);
+	i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
+				  data->temp_hyst);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+			   char *buf)
+{
+	struct lm90_data *data = lm90_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = lm90_update_device(dev);
+	int bitnr = attr->index;
+
+	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static ssize_t show_update_interval(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL,
+	0, LOCAL_TEMP);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL,
+	0, REMOTE_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, LOCAL_LOW);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 0, REMOTE_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, LOCAL_HIGH);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 1, REMOTE_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, LOCAL_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, REMOTE_CRIT);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
+	set_temphyst, LOCAL_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL,
+	REMOTE_CRIT);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 2, REMOTE_OFFSET);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+		   set_update_interval);
+
+static struct attribute *lm90_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_group = {
+	.attrs = lm90_attributes,
+};
+
+static struct attribute *lm90_temp2_offset_attributes[] = {
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_temp2_offset_group = {
+	.attrs = lm90_temp2_offset_attributes,
+};
+
+/*
+ * Additional attributes for devices with emergency sensors
+ */
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, LOCAL_EMERG);
+static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, REMOTE_EMERG);
+static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, LOCAL_EMERG);
+static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, REMOTE_EMERG);
+
+static struct attribute *lm90_emergency_attributes[] = {
+	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_emergency_group = {
+	.attrs = lm90_emergency_attributes,
+};
+
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+static struct attribute *lm90_emergency_alarm_attributes[] = {
+	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_emergency_alarm_group = {
+	.attrs = lm90_emergency_alarm_attributes,
+};
+
+/*
+ * Additional attributes for devices with 3 temperature sensors
+ */
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL,
+	0, REMOTE2_TEMP);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 3, REMOTE2_LOW);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 4, REMOTE2_HIGH);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, REMOTE2_CRIT);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL,
+	REMOTE2_CRIT);
+static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, REMOTE2_EMERG);
+static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, REMOTE2_EMERG);
+
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+static struct attribute *lm90_temp3_attributes[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_temp3_group = {
+	.attrs = lm90_temp3_attributes,
+};
+
+/* pec used for ADM1032 only */
+static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
+			char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
+}
+
+static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
+		       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	switch (val) {
+	case 0:
+		client->flags &= ~I2C_CLIENT_PEC;
+		break;
+	case 1:
+		client->flags |= I2C_CLIENT_PEC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm90_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	const char *name = NULL;
+	int man_id, chip_id, config1, config2, convrate;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* detection and identification */
+	man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID);
+	chip_id = i2c_smbus_read_byte_data(client, LM90_REG_R_CHIP_ID);
+	config1 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1);
+	convrate = i2c_smbus_read_byte_data(client, LM90_REG_R_CONVRATE);
+	if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
+		return -ENODEV;
+
+	if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) {
+		config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2);
+		if (config2 < 0)
+			return -ENODEV;
+	} else
+		config2 = 0;		/* Make compiler happy */
+
+	if ((address == 0x4C || address == 0x4D)
+	 && man_id == 0x01) { /* National Semiconductor */
+		if ((config1 & 0x2A) == 0x00
+		 && (config2 & 0xF8) == 0x00
+		 && convrate <= 0x09) {
+			if (address == 0x4C
+			 && (chip_id & 0xF0) == 0x20) { /* LM90 */
+				name = "lm90";
+			} else
+			if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */
+				name = "lm99";
+				dev_info(&adapter->dev,
+					 "Assuming LM99 chip at 0x%02x\n",
+					 address);
+				dev_info(&adapter->dev,
+					 "If it is an LM89, instantiate it "
+					 "with the new_device sysfs "
+					 "interface\n");
+			} else
+			if (address == 0x4C
+			 && (chip_id & 0xF0) == 0x10) { /* LM86 */
+				name = "lm86";
+			}
+		}
+	} else
+	if ((address == 0x4C || address == 0x4D)
+	 && man_id == 0x41) { /* Analog Devices */
+		if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
+		 && (config1 & 0x3F) == 0x00
+		 && convrate <= 0x0A) {
+			name = "adm1032";
+			/*
+			 * The ADM1032 supports PEC, but only if combined
+			 * transactions are not used.
+			 */
+			if (i2c_check_functionality(adapter,
+						    I2C_FUNC_SMBUS_BYTE))
+				info->flags |= I2C_CLIENT_PEC;
+		} else
+		if (chip_id == 0x51 /* ADT7461 */
+		 && (config1 & 0x1B) == 0x00
+		 && convrate <= 0x0A) {
+			name = "adt7461";
+		} else
+		if (chip_id == 0x57 /* ADT7461A, NCT1008 */
+		 && (config1 & 0x1B) == 0x00
+		 && convrate <= 0x0A) {
+			name = "adt7461a";
+		}
+	} else
+	if (man_id == 0x4D) { /* Maxim */
+		int emerg, emerg2, status2;
+
+		/*
+		 * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read
+		 * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG
+		 * exists, both readings will reflect the same value. Otherwise,
+		 * the readings will be different.
+		 */
+		emerg = i2c_smbus_read_byte_data(client,
+						 MAX6659_REG_R_REMOTE_EMERG);
+		man_id = i2c_smbus_read_byte_data(client,
+						  LM90_REG_R_MAN_ID);
+		emerg2 = i2c_smbus_read_byte_data(client,
+						  MAX6659_REG_R_REMOTE_EMERG);
+		status2 = i2c_smbus_read_byte_data(client,
+						   MAX6696_REG_R_STATUS2);
+		if (emerg < 0 || man_id < 0 || emerg2 < 0 || status2 < 0)
+			return -ENODEV;
+
+		/*
+		 * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
+		 * register. Reading from that address will return the last
+		 * read value, which in our case is those of the man_id
+		 * register. Likewise, the config1 register seems to lack a
+		 * low nibble, so the value will be those of the previous
+		 * read, so in our case those of the man_id register.
+		 * MAX6659 has a third set of upper temperature limit registers.
+		 * Those registers also return values on MAX6657 and MAX6658,
+		 * thus the only way to detect MAX6659 is by its address.
+		 * For this reason it will be mis-detected as MAX6657 if its
+		 * address is 0x4C.
+		 */
+		if (chip_id == man_id
+		 && (address == 0x4C || address == 0x4D || address == 0x4E)
+		 && (config1 & 0x1F) == (man_id & 0x0F)
+		 && convrate <= 0x09) {
+			if (address == 0x4C)
+				name = "max6657";
+			else
+				name = "max6659";
+		} else
+		/*
+		 * Even though MAX6695 and MAX6696 do not have a chip ID
+		 * register, reading it returns 0x01. Bit 4 of the config1
+		 * register is unused and should return zero when read. Bit 0 of
+		 * the status2 register is unused and should return zero when
+		 * read.
+		 *
+		 * MAX6695 and MAX6696 have an additional set of temperature
+		 * limit registers. We can detect those chips by checking if
+		 * one of those registers exists.
+		 */
+		if (chip_id == 0x01
+		 && (config1 & 0x10) == 0x00
+		 && (status2 & 0x01) == 0x00
+		 && emerg == emerg2
+		 && convrate <= 0x07) {
+			name = "max6696";
+		} else
+		/*
+		 * The chip_id register of the MAX6680 and MAX6681 holds the
+		 * revision of the chip. The lowest bit of the config1 register
+		 * is unused and should return zero when read, so should the
+		 * second to last bit of config1 (software reset).
+		 */
+		if (chip_id == 0x01
+		 && (config1 & 0x03) == 0x00
+		 && convrate <= 0x07) {
+			name = "max6680";
+		} else
+		/*
+		 * The chip_id register of the MAX6646/6647/6649 holds the
+		 * revision of the chip. The lowest 6 bits of the config1
+		 * register are unused and should return zero when read.
+		 */
+		if (chip_id == 0x59
+		 && (config1 & 0x3f) == 0x00
+		 && convrate <= 0x07) {
+			name = "max6646";
+		}
+	} else
+	if (address == 0x4C
+	 && man_id == 0x5C) { /* Winbond/Nuvoton */
+		if ((config1 & 0x2A) == 0x00
+		 && (config2 & 0xF8) == 0x00) {
+			if (chip_id == 0x01 /* W83L771W/G */
+			 && convrate <= 0x09) {
+				name = "w83l771";
+			} else
+			if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
+			 && convrate <= 0x08) {
+				name = "w83l771";
+			}
+		}
+	} else
+	if (address >= 0x48 && address <= 0x4F
+	 && man_id == 0xA1) { /*  NXP Semiconductor/Philips */
+		if (chip_id == 0x00
+		 && (config1 & 0x2A) == 0x00
+		 && (config2 & 0xFE) == 0x00
+		 && convrate <= 0x09) {
+			name = "sa56004";
+		}
+	} else
+	if ((address == 0x4C || address == 0x4D)
+	 && man_id == 0x47) { /* GMT */
+		if (chip_id == 0x01 /* G781 */
+		 && (config1 & 0x3F) == 0x00
+		 && convrate <= 0x08)
+			name = "g781";
+	} else
+	if (address == 0x4C
+	 && man_id == 0x55) { /* Texas Instruments */
+		int local_ext;
+
+		local_ext = i2c_smbus_read_byte_data(client,
+						     TMP451_REG_R_LOCAL_TEMPL);
+
+		if (chip_id == 0x00 /* TMP451 */
+		 && (config1 & 0x1B) == 0x00
+		 && convrate <= 0x09
+		 && (local_ext & 0x0F) == 0x00)
+			name = "tmp451";
+	}
+
+	if (!name) { /* identification failed */
+		dev_dbg(&adapter->dev,
+			"Unsupported chip at 0x%02x (man_id=0x%02X, "
+			"chip_id=0x%02X)\n", address, man_id, chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
+{
+	/* Restore initial configuration */
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
+				  data->convrate_orig);
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+				  data->config_orig);
+}
+
+static void lm90_init_client(struct i2c_client *client, struct lm90_data *data)
+{
+	u8 config, convrate;
+
+	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
+		dev_warn(&client->dev, "Failed to read convrate register!\n");
+		convrate = LM90_DEF_CONVRATE_RVAL;
+	}
+	data->convrate_orig = convrate;
+
+	/*
+	 * Start the conversions.
+	 */
+	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
+	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
+		dev_warn(&client->dev, "Initialization failed!\n");
+		return;
+	}
+	data->config_orig = config;
+
+	/* Check Temperature Range Select */
+	if (data->kind == adt7461 || data->kind == tmp451) {
+		if (config & 0x04)
+			data->flags |= LM90_FLAG_ADT7461_EXT;
+	}
+
+	/*
+	 * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+	 * 0.125 degree resolution) and range (0x08, extend range
+	 * to -64 degree) mode for the remote temperature sensor.
+	 */
+	if (data->kind == max6680)
+		config |= 0x18;
+
+	/*
+	 * Select external channel 0 for max6695/96
+	 */
+	if (data->kind == max6696)
+		config &= ~0x08;
+
+	config &= 0xBF;	/* run */
+	if (config != data->config_orig) /* Only write if changed */
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+}
+
+static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
+{
+	struct lm90_data *data = i2c_get_clientdata(client);
+	u8 st, st2 = 0;
+
+	lm90_read_reg(client, LM90_REG_R_STATUS, &st);
+
+	if (data->kind == max6696)
+		lm90_read_reg(client, MAX6696_REG_R_STATUS2, &st2);
+
+	*status = st | (st2 << 8);
+
+	if ((st & 0x7f) == 0 && (st2 & 0xfe) == 0)
+		return false;
+
+	if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
+	    (st2 & MAX6696_STATUS2_LOT2))
+		dev_warn(&client->dev,
+			 "temp%d out of range, please check!\n", 1);
+	if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
+	    (st2 & MAX6696_STATUS2_ROT2))
+		dev_warn(&client->dev,
+			 "temp%d out of range, please check!\n", 2);
+	if (st & LM90_STATUS_ROPEN)
+		dev_warn(&client->dev,
+			 "temp%d diode open, please check!\n", 2);
+	if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
+		   MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
+		dev_warn(&client->dev,
+			 "temp%d out of range, please check!\n", 3);
+	if (st2 & MAX6696_STATUS2_R2OPEN)
+		dev_warn(&client->dev,
+			 "temp%d diode open, please check!\n", 3);
+
+	return true;
+}
+
+static irqreturn_t lm90_irq_thread(int irq, void *dev_id)
+{
+	struct i2c_client *client = dev_id;
+	u16 status;
+
+	if (lm90_is_tripped(client, &status))
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static int lm90_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct i2c_adapter *adapter = to_i2c_adapter(dev->parent);
+	struct lm90_data *data;
+	struct regulator *regulator;
+	int groups = 0;
+	int err;
+
+	regulator = devm_regulator_get(dev, "vcc");
+	if (IS_ERR(regulator))
+		return PTR_ERR(regulator);
+
+	err = regulator_enable(regulator);
+	if (err < 0) {
+		dev_err(dev, "Failed to enable regulator: %d\n", err);
+		return err;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	data->regulator = regulator;
+
+	/* Set the device type */
+	data->kind = id->driver_data;
+	if (data->kind == adm1032) {
+		if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+			client->flags &= ~I2C_CLIENT_PEC;
+	}
+
+	/*
+	 * Different devices have different alarm bits triggering the
+	 * ALERT# output
+	 */
+	data->alert_alarms = lm90_params[data->kind].alert_alarms;
+
+	/* Set chip capabilities */
+	data->flags = lm90_params[data->kind].flags;
+	data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
+
+	/* Set maximum conversion rate */
+	data->max_convrate = lm90_params[data->kind].max_convrate;
+
+	/* Initialize the LM90 chip */
+	lm90_init_client(client, data);
+
+	/* Register sysfs hooks */
+	data->groups[groups++] = &lm90_group;
+
+	if (data->flags & LM90_HAVE_OFFSET)
+		data->groups[groups++] = &lm90_temp2_offset_group;
+
+	if (data->flags & LM90_HAVE_EMERGENCY)
+		data->groups[groups++] = &lm90_emergency_group;
+
+	if (data->flags & LM90_HAVE_EMERGENCY_ALARM)
+		data->groups[groups++] = &lm90_emergency_alarm_group;
+
+	if (data->flags & LM90_HAVE_TEMP3)
+		data->groups[groups++] = &lm90_temp3_group;
+
+	if (client->flags & I2C_CLIENT_PEC) {
+		err = device_create_file(dev, &dev_attr_pec);
+		if (err)
+			goto exit_restore;
+	}
+
+	data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+							    data, data->groups);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_pec;
+	}
+
+	if (client->irq) {
+		dev_dbg(dev, "IRQ: %d\n", client->irq);
+		err = devm_request_threaded_irq(dev, client->irq,
+						NULL, lm90_irq_thread,
+						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+						"lm90", client);
+		if (err < 0) {
+			dev_err(dev, "cannot request IRQ %d\n", client->irq);
+			goto exit_unregister;
+		}
+	}
+
+	return 0;
+
+exit_unregister:
+	hwmon_device_unregister(data->hwmon_dev);
+exit_remove_pec:
+	device_remove_file(dev, &dev_attr_pec);
+exit_restore:
+	lm90_restore_conf(client, data);
+	regulator_disable(data->regulator);
+
+	return err;
+}
+
+static int lm90_remove(struct i2c_client *client)
+{
+	struct lm90_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	device_remove_file(&client->dev, &dev_attr_pec);
+	lm90_restore_conf(client, data);
+	regulator_disable(data->regulator);
+
+	return 0;
+}
+
+static void lm90_alert(struct i2c_client *client, unsigned int flag)
+{
+	u16 alarms;
+
+	if (lm90_is_tripped(client, &alarms)) {
+		/*
+		 * Disable ALERT# output, because these chips don't implement
+		 * SMBus alert correctly; they should only hold the alert line
+		 * low briefly.
+		 */
+		struct lm90_data *data = i2c_get_clientdata(client);
+
+		if ((data->flags & LM90_HAVE_BROKEN_ALERT)
+		 && (alarms & data->alert_alarms)) {
+			u8 config;
+			dev_dbg(&client->dev, "Disabling ALERT#\n");
+			lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+			i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+						  config | 0x80);
+		}
+	} else {
+		dev_info(&client->dev, "Everything OK\n");
+	}
+}
+
+static struct i2c_driver lm90_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm90",
+	},
+	.probe		= lm90_probe,
+	.remove		= lm90_remove,
+	.alert		= lm90_alert,
+	.id_table	= lm90_id,
+	.detect		= lm90_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm90_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("LM90/ADM1032 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
new file mode 100644
index 0000000..cfaf70b
--- /dev/null
+++ b/drivers/hwmon/lm92.c
@@ -0,0 +1,411 @@
+/*
+ * lm92 - Hardware monitoring driver
+ * Copyright (C) 2005-2008  Jean Delvare <jdelvare@suse.de>
+ *
+ * Based on the lm90 driver, with some ideas taken from the lm_sensors
+ * lm92 driver as well.
+ *
+ * The LM92 is a sensor chip made by National Semiconductor. It reports
+ * its own temperature with a 0.0625 deg resolution and a 0.33 deg
+ * accuracy. Complete datasheet can be obtained from National's website
+ * at:
+ *   http://www.national.com/pf/LM/LM92.html
+ *
+ * This driver also supports the MAX6635 sensor chip made by Maxim.
+ * This chip is compatible with the LM92, but has a lesser accuracy
+ * (1.0 deg). Complete datasheet can be obtained from Maxim's website
+ * at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
+ *
+ * Since the LM92 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * Support could easily be added for the National Semiconductor LM76
+ * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible
+ * with the LM92.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+/*
+ * The LM92 and MAX6635 have 2 two-state pins for address selection,
+ * resulting in 4 possible addresses.
+ */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+						I2C_CLIENT_END };
+
+/* The LM92 registers */
+#define LM92_REG_CONFIG			0x01 /* 8-bit, RW */
+#define LM92_REG_TEMP			0x00 /* 16-bit, RO */
+#define LM92_REG_TEMP_HYST		0x02 /* 16-bit, RW */
+#define LM92_REG_TEMP_CRIT		0x03 /* 16-bit, RW */
+#define LM92_REG_TEMP_LOW		0x04 /* 16-bit, RW */
+#define LM92_REG_TEMP_HIGH		0x05 /* 16-bit, RW */
+#define LM92_REG_MAN_ID			0x07 /* 16-bit, RO, LM92 only */
+
+/*
+ * The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius,
+ * left-justified in 16-bit registers. No rounding is done, with such
+ * a resolution it's just not worth it. Note that the MAX6635 doesn't
+ * make use of the 4 lower bits for limits (i.e. effective resolution
+ * for limits is 1 degree Celsius).
+ */
+static inline int TEMP_FROM_REG(s16 reg)
+{
+	return reg / 8 * 625 / 10;
+}
+
+static inline s16 TEMP_TO_REG(long val)
+{
+	val = clamp_val(val, -60000, 160000);
+	return val * 10 / 625 * 8;
+}
+
+/* Alarm flags are stored in the 3 LSB of the temperature register */
+static inline u8 ALARMS_FROM_REG(s16 reg)
+{
+	return reg & 0x0007;
+}
+
+enum temp_index {
+	t_input,
+	t_crit,
+	t_min,
+	t_max,
+	t_hyst,
+	t_num_regs
+};
+
+static const u8 regs[t_num_regs] = {
+	[t_input] = LM92_REG_TEMP,
+	[t_crit] = LM92_REG_TEMP_CRIT,
+	[t_min] = LM92_REG_TEMP_LOW,
+	[t_max] = LM92_REG_TEMP_HIGH,
+	[t_hyst] = LM92_REG_TEMP_HYST,
+};
+
+/* Client data (each client gets its own) */
+struct lm92_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	s16 temp[t_num_regs];	/* index with enum temp_index */
+};
+
+/*
+ * Sysfs attributes and callback functions
+ */
+
+static struct lm92_data *lm92_update_device(struct device *dev)
+{
+	struct lm92_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ)
+	 || !data->valid) {
+		dev_dbg(&client->dev, "Updating lm92 data\n");
+		for (i = 0; i < t_num_regs; i++) {
+			data->temp[i] =
+				i2c_smbus_read_word_swapped(client, regs[i]);
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+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 lm92_data *data = lm92_update_device(dev);
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm92_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int nr = attr->index;
+	long val;
+	int err;
+	
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = TEMP_TO_REG(val);
+	i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_hyst(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
+		       - TEMP_FROM_REG(data->temp[t_hyst]));
+}
+
+static ssize_t show_temp_min_hyst(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
+		       + TEMP_FROM_REG(data->temp[t_hyst]));
+}
+
+static ssize_t set_temp_hyst(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm92_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = clamp_val(val, -120000, 220000);
+	mutex_lock(&data->update_lock);
+	 data->temp[t_hyst] =
+		TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val);
+	i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
+				     data->temp[t_hyst]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_crit);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+			  set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_min);
+static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_max);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
+
+/*
+ * Detection and registration
+ */
+
+static void lm92_init_client(struct i2c_client *client)
+{
+	u8 config;
+
+	/* Start the conversions if needed */
+	config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	if (config & 0x01)
+		i2c_smbus_write_byte_data(client, LM92_REG_CONFIG,
+					  config & 0xFE);
+}
+
+/*
+ * The MAX6635 has no identification register, so we have to use tricks
+ * to identify it reliably. This is somewhat slow.
+ * Note that we do NOT rely on the 2 MSB of the configuration register
+ * always reading 0, as suggested by the datasheet, because it was once
+ * reported not to be true.
+ */
+static int max6635_check(struct i2c_client *client)
+{
+	u16 temp_low, temp_high, temp_hyst, temp_crit;
+	u8 conf;
+	int i;
+
+	/*
+	 * No manufacturer ID register, so a read from this address will
+	 * always return the last read value.
+	 */
+	temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)
+		return 0;
+	temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high)
+		return 0;
+
+	/* Limits are stored as integer values (signed, 9-bit). */
+	if ((temp_low & 0x7f00) || (temp_high & 0x7f00))
+		return 0;
+	temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST);
+	temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT);
+	if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
+		return 0;
+
+	/*
+	 * Registers addresses were found to cycle over 16-byte boundaries.
+	 * We don't test all registers with all offsets so as to save some
+	 * reads and time, but this should still be sufficient to dismiss
+	 * non-MAX6635 chips.
+	 */
+	conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	for (i = 16; i < 96; i *= 2) {
+		if (temp_hyst != i2c_smbus_read_word_data(client,
+				 LM92_REG_TEMP_HYST + i - 16)
+		 || temp_crit != i2c_smbus_read_word_data(client,
+				 LM92_REG_TEMP_CRIT + i)
+		 || temp_low != i2c_smbus_read_word_data(client,
+				LM92_REG_TEMP_LOW + i + 16)
+		 || temp_high != i2c_smbus_read_word_data(client,
+				 LM92_REG_TEMP_HIGH + i + 32)
+		 || conf != i2c_smbus_read_byte_data(client,
+			    LM92_REG_CONFIG + i))
+			return 0;
+	}
+
+	return 1;
+}
+
+static struct attribute *lm92_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&dev_attr_temp1_min_hyst.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm92);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm92_detect(struct i2c_client *new_client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	u8 config;
+	u16 man_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+					    | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	config = i2c_smbus_read_byte_data(new_client, LM92_REG_CONFIG);
+	man_id = i2c_smbus_read_word_data(new_client, LM92_REG_MAN_ID);
+
+	if ((config & 0xe0) == 0x00 && man_id == 0x0180)
+		pr_info("lm92: Found National Semiconductor LM92 chip\n");
+	else if (max6635_check(new_client))
+		pr_info("lm92: Found Maxim MAX6635 chip\n");
+	else
+		return -ENODEV;
+
+	strlcpy(info->type, "lm92", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int lm92_probe(struct i2c_client *new_client,
+		      const struct i2c_device_id *id)
+{
+	struct device *hwmon_dev;
+	struct lm92_data *data;
+
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = new_client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the chipset */
+	lm92_init_client(new_client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+							   new_client->name,
+							   data, lm92_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+
+/*
+ * Module and driver stuff
+ */
+
+static const struct i2c_device_id lm92_id[] = {
+	{ "lm92", 0 },
+	/* max6635 could be added here */
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm92_id);
+
+static struct i2c_driver lm92_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm92",
+	},
+	.probe		= lm92_probe,
+	.id_table	= lm92_id,
+	.detect		= lm92_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm92_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("LM92/MAX6635 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
new file mode 100644
index 0000000..90bb048
--- /dev/null
+++ b/drivers/hwmon/lm93.c
@@ -0,0 +1,2788 @@
+/*
+ * lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ *
+ * Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+ *	Copyright (c) 2004 Utilitek Systems, Inc.
+ *
+ * derived in part from lm78.c:
+ *	Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *
+ * derived in part from lm85.c:
+ *	Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
+ *	Copyright (c) 2003       Margit Schubert-While <margitsw@t-online.de>
+ *
+ * derived in part from w83l785ts.c:
+ *	Copyright (c) 2003-2004 Jean Delvare <jdelvare@suse.de>
+ *
+ * Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+ *	Copyright (c) 2005 Aspen Systems, Inc.
+ *
+ * Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
+ *	Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
+ *
+ * Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
+ *	Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
+ *
+ * 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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+/* LM93 REGISTER ADDRESSES */
+
+/* miscellaneous */
+#define LM93_REG_MFR_ID			0x3e
+#define LM93_REG_VER			0x3f
+#define LM93_REG_STATUS_CONTROL		0xe2
+#define LM93_REG_CONFIG			0xe3
+#define LM93_REG_SLEEP_CONTROL		0xe4
+
+/* alarm values start here */
+#define LM93_REG_HOST_ERROR_1		0x48
+
+/* voltage inputs: in1-in16 (nr => 0-15) */
+#define LM93_REG_IN(nr)			(0x56 + (nr))
+#define LM93_REG_IN_MIN(nr)		(0x90 + (nr) * 2)
+#define LM93_REG_IN_MAX(nr)		(0x91 + (nr) * 2)
+
+/* temperature inputs: temp1-temp4 (nr => 0-3) */
+#define LM93_REG_TEMP(nr)		(0x50 + (nr))
+#define LM93_REG_TEMP_MIN(nr)		(0x78 + (nr) * 2)
+#define LM93_REG_TEMP_MAX(nr)		(0x79 + (nr) * 2)
+
+/* temp[1-4]_auto_boost (nr => 0-3) */
+#define LM93_REG_BOOST(nr)		(0x80 + (nr))
+
+/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */
+#define LM93_REG_PROCHOT_CUR(nr)	(0x67 + (nr) * 2)
+#define LM93_REG_PROCHOT_AVG(nr)	(0x68 + (nr) * 2)
+#define LM93_REG_PROCHOT_MAX(nr)	(0xb0 + (nr))
+
+/* fan tach inputs: fan1-fan4 (nr => 0-3) */
+#define LM93_REG_FAN(nr)		(0x6e + (nr) * 2)
+#define LM93_REG_FAN_MIN(nr)		(0xb4 + (nr) * 2)
+
+/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */
+#define LM93_REG_PWM_CTL(nr, reg)	(0xc8 + (reg) + (nr) * 4)
+#define LM93_PWM_CTL1	0x0
+#define LM93_PWM_CTL2	0x1
+#define LM93_PWM_CTL3	0x2
+#define LM93_PWM_CTL4	0x3
+
+/* GPIO input state */
+#define LM93_REG_GPI			0x6b
+
+/* vid inputs: vid1-vid2 (nr => 0-1) */
+#define LM93_REG_VID(nr)		(0x6c + (nr))
+
+/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */
+#define LM93_REG_VCCP_LIMIT_OFF(nr)	(0xb2 + (nr))
+
+/* temp[1-4]_auto_boost_hyst */
+#define LM93_REG_BOOST_HYST_12		0xc0
+#define LM93_REG_BOOST_HYST_34		0xc1
+#define LM93_REG_BOOST_HYST(nr)		(0xc0 + (nr)/2)
+
+/* temp[1-4]_auto_pwm_[min|hyst] */
+#define LM93_REG_PWM_MIN_HYST_12	0xc3
+#define LM93_REG_PWM_MIN_HYST_34	0xc4
+#define LM93_REG_PWM_MIN_HYST(nr)	(0xc3 + (nr)/2)
+
+/* prochot_override & prochot_interval */
+#define LM93_REG_PROCHOT_OVERRIDE	0xc6
+#define LM93_REG_PROCHOT_INTERVAL	0xc7
+
+/* temp[1-4]_auto_base (nr => 0-3) */
+#define LM93_REG_TEMP_BASE(nr)		(0xd0 + (nr))
+
+/* temp[1-4]_auto_offsets (step => 0-11) */
+#define LM93_REG_TEMP_OFFSET(step)	(0xd4 + (step))
+
+/* #PROCHOT & #VRDHOT PWM ramp control */
+#define LM93_REG_PWM_RAMP_CTL		0xbf
+
+/* miscellaneous */
+#define LM93_REG_SFC1		0xbc
+#define LM93_REG_SFC2		0xbd
+#define LM93_REG_GPI_VID_CTL	0xbe
+#define LM93_REG_SF_TACH_TO_PWM	0xe0
+
+/* error masks */
+#define LM93_REG_GPI_ERR_MASK	0xec
+#define LM93_REG_MISC_ERR_MASK	0xed
+
+/* LM93 REGISTER VALUES */
+#define LM93_MFR_ID		0x73
+#define LM93_MFR_ID_PROTOTYPE	0x72
+
+/* LM94 REGISTER VALUES */
+#define LM94_MFR_ID_2		0x7a
+#define LM94_MFR_ID		0x79
+#define LM94_MFR_ID_PROTOTYPE	0x78
+
+/* SMBus capabilities */
+#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
+#define LM93_SMBUS_FUNC_MIN  (I2C_FUNC_SMBUS_BYTE_DATA | \
+		I2C_FUNC_SMBUS_WORD_DATA)
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+
+static bool disable_block;
+module_param(disable_block, bool, 0);
+MODULE_PARM_DESC(disable_block,
+	"Set to non-zero to disable SMBus block data transactions.");
+
+static bool init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
+
+static int vccp_limit_type[2] = {0, 0};
+module_param_array(vccp_limit_type, int, NULL, 0);
+MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes.");
+
+static int vid_agtl;
+module_param(vid_agtl, int, 0);
+MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds.");
+
+/* Driver data */
+static struct i2c_driver lm93_driver;
+
+/* LM93 BLOCK READ COMMANDS */
+static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
+	{ 0xf2,  8 },
+	{ 0xf3,  8 },
+	{ 0xf4,  6 },
+	{ 0xf5, 16 },
+	{ 0xf6,  4 },
+	{ 0xf7,  8 },
+	{ 0xf8, 12 },
+	{ 0xf9, 32 },
+	{ 0xfa,  8 },
+	{ 0xfb,  8 },
+	{ 0xfc, 16 },
+	{ 0xfd,  9 },
+};
+
+/*
+ * ALARMS: SYSCTL format described further below
+ * REG: 64 bits in 8 registers, as immediately below
+ */
+struct block1_t {
+	u8 host_status_1;
+	u8 host_status_2;
+	u8 host_status_3;
+	u8 host_status_4;
+	u8 p1_prochot_status;
+	u8 p2_prochot_status;
+	u8 gpi_status;
+	u8 fan_status;
+};
+
+/*
+ * Client-specific data
+ */
+struct lm93_data {
+	struct i2c_client *client;
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+
+	/* client update function */
+	void (*update)(struct lm93_data *, struct i2c_client *);
+
+	char valid; /* !=0 if following fields are valid */
+
+	/* register values, arranged by block read groups */
+	struct block1_t block1;
+
+	/*
+	 * temp1 - temp4: unfiltered readings
+	 * temp1 - temp2: filtered readings
+	 */
+	u8 block2[6];
+
+	/* vin1 - vin16: readings */
+	u8 block3[16];
+
+	/* prochot1 - prochot2: readings */
+	struct {
+		u8 cur;
+		u8 avg;
+	} block4[2];
+
+	/* fan counts 1-4 => 14-bits, LE, *left* justified */
+	u16 block5[4];
+
+	/* block6 has a lot of data we don't need */
+	struct {
+		u8 min;
+		u8 max;
+	} temp_lim[4];
+
+	/* vin1 - vin16: low and high limits */
+	struct {
+		u8 min;
+		u8 max;
+	} block7[16];
+
+	/* fan count limits 1-4 => same format as block5 */
+	u16 block8[4];
+
+	/* pwm control registers (2 pwms, 4 regs) */
+	u8 block9[2][4];
+
+	/* auto/pwm base temp and offset temp registers */
+	struct {
+		u8 base[4];
+		u8 offset[12];
+	} block10;
+
+	/* master config register */
+	u8 config;
+
+	/* VID1 & VID2 => register format, 6-bits, right justified */
+	u8 vid[2];
+
+	/* prochot1 - prochot2: limits */
+	u8 prochot_max[2];
+
+	/* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */
+	u8 vccp_limits[2];
+
+	/* GPIO input state (register format, i.e. inverted) */
+	u8 gpi;
+
+	/* #PROCHOT override (register format) */
+	u8 prochot_override;
+
+	/* #PROCHOT intervals (register format) */
+	u8 prochot_interval;
+
+	/* Fan Boost Temperatures (register format) */
+	u8 boost[4];
+
+	/* Fan Boost Hysteresis (register format) */
+	u8 boost_hyst[2];
+
+	/* Temperature Zone Min. PWM & Hysteresis (register format) */
+	u8 auto_pwm_min_hyst[2];
+
+	/* #PROCHOT & #VRDHOT PWM Ramp Control */
+	u8 pwm_ramp_ctl;
+
+	/* miscellaneous setup regs */
+	u8 sfc1;
+	u8 sfc2;
+	u8 sf_tach_to_pwm;
+
+	/*
+	 * The two PWM CTL2  registers can read something other than what was
+	 * last written for the OVR_DC field (duty cycle override).  So, we
+	 * save the user-commanded value here.
+	 */
+	u8 pwm_override[2];
+};
+
+/*
+ * VID:	mV
+ * REG: 6-bits, right justified, *always* using Intel VRM/VRD 10
+ */
+static int LM93_VID_FROM_REG(u8 reg)
+{
+	return vid_from_reg((reg & 0x3f), 100);
+}
+
+/* min, max, and nominal register values, per channel (u8) */
+static const u8 lm93_vin_reg_min[16] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae,
+};
+static const u8 lm93_vin_reg_max[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
+};
+/*
+ * Values from the datasheet. They're here for documentation only.
+ * static const u8 lm93_vin_reg_nom[16] = {
+ * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
+ * };
+ */
+
+/* min, max, and nominal voltage readings, per channel (mV)*/
+static const unsigned long lm93_vin_val_min[16] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 3000,
+};
+
+static const unsigned long lm93_vin_val_max[16] = {
+	1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
+	4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
+};
+/*
+ * Values from the datasheet. They're here for documentation only.
+ * static const unsigned long lm93_vin_val_nom[16] = {
+ * 927,  927,  927, 1200, 1500, 1500, 1200, 1200,
+ * 3300, 5000, 2500, 1969,  984,  984,  309, 3300,
+ * };
+ */
+
+static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
+{
+	const long uv_max = lm93_vin_val_max[nr] * 1000;
+	const long uv_min = lm93_vin_val_min[nr] * 1000;
+
+	const long slope = (uv_max - uv_min) /
+		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+	const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
+
+	return (slope * reg + intercept + 500) / 1000;
+}
+
+/*
+ * IN: mV, limits determined by channel nr
+ * REG: scaling determined by channel nr
+ */
+static u8 LM93_IN_TO_REG(int nr, unsigned val)
+{
+	/* range limit */
+	const long mv = clamp_val(val,
+				  lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+
+	/* try not to lose too much precision here */
+	const long uv = mv * 1000;
+	const long uv_max = lm93_vin_val_max[nr] * 1000;
+	const long uv_min = lm93_vin_val_min[nr] * 1000;
+
+	/* convert */
+	const long slope = (uv_max - uv_min) /
+		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+	const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
+
+	u8 result = ((uv - intercept + (slope/2)) / slope);
+	result = clamp_val(result,
+			   lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+	return result;
+}
+
+/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
+static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
+{
+	const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+				(((reg >> 0 & 0x0f) + 1) * -25000);
+	const long uv_vid = vid * 1000;
+	return (uv_vid + uv_offset + 5000) / 10000;
+}
+
+#define LM93_IN_MIN_FROM_REG(reg, vid)	LM93_IN_REL_FROM_REG((reg), 0, (vid))
+#define LM93_IN_MAX_FROM_REG(reg, vid)	LM93_IN_REL_FROM_REG((reg), 1, (vid))
+
+/*
+ * vid in mV , upper == 0 indicates low limit, otherwise upper limit
+ * upper also determines which nibble of the register is returned
+ * (the other nibble will be 0x0)
+ */
+static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+{
+	long uv_offset = vid * 1000 - val * 10000;
+	if (upper) {
+		uv_offset = clamp_val(uv_offset, 12500, 200000);
+		return (u8)((uv_offset /  12500 - 1) << 4);
+	} else {
+		uv_offset = clamp_val(uv_offset, -400000, -25000);
+		return (u8)((uv_offset / -25000 - 1) << 0);
+	}
+}
+
+/*
+ * TEMP: 1/1000 degrees C (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static int LM93_TEMP_FROM_REG(u8 reg)
+{
+	return (s8)reg * 1000;
+}
+
+#define LM93_TEMP_MIN (-128000)
+#define LM93_TEMP_MAX (127000)
+
+/*
+ * TEMP: 1/1000 degrees C (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static u8 LM93_TEMP_TO_REG(long temp)
+{
+	int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
+}
+
+/* Determine 4-bit temperature offset resolution */
+static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
+{
+	/* mode: 0 => 1C/bit, nonzero => 0.5C/bit */
+	return sfc2 & (nr < 2 ? 0x10 : 0x20);
+}
+
+/*
+ * This function is common to all 4-bit temperature offsets
+ * reg is 4 bits right justified
+ * mode 0 => 1C/bit, mode !0 => 0.5C/bit
+ */
+static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
+{
+	return (reg & 0x0f) * (mode ? 5 : 10);
+}
+
+#define LM93_TEMP_OFFSET_MIN  (0)
+#define LM93_TEMP_OFFSET_MAX0 (150)
+#define LM93_TEMP_OFFSET_MAX1 (75)
+
+/*
+ * This function is common to all 4-bit temperature offsets
+ * returns 4 bits right justified
+ * mode 0 => 1C/bit, mode !0 => 0.5C/bit
+ */
+static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
+{
+	int factor = mode ? 5 : 10;
+
+	off = clamp_val(off, LM93_TEMP_OFFSET_MIN,
+		mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
+	return (u8)((off + factor/2) / factor);
+}
+
+/* 0 <= nr <= 3 */
+static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
+{
+	/* temp1-temp2 (nr=0,1) use lower nibble */
+	if (nr < 2)
+		return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode);
+
+	/* temp3-temp4 (nr=2,3) use upper nibble */
+	else
+		return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
+}
+
+/*
+ * TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
+ * REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
+ * 0 <= nr <= 3
+ */
+static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
+{
+	u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
+
+	/* temp1-temp2 (nr=0,1) use lower nibble */
+	if (nr < 2)
+		return (old & 0xf0) | (new & 0x0f);
+
+	/* temp3-temp4 (nr=2,3) use upper nibble */
+	else
+		return (new << 4 & 0xf0) | (old & 0x0f);
+}
+
+static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr,
+		int mode)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = data->boost_hyst[0] & 0x0f;
+		break;
+	case 1:
+		reg = data->boost_hyst[0] >> 4 & 0x0f;
+		break;
+	case 2:
+		reg = data->boost_hyst[1] & 0x0f;
+		break;
+	case 3:
+	default:
+		reg = data->boost_hyst[1] >> 4 & 0x0f;
+		break;
+	}
+
+	return LM93_TEMP_FROM_REG(data->boost[nr]) -
+			LM93_TEMP_OFFSET_FROM_REG(reg, mode);
+}
+
+static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
+		int nr, int mode)
+{
+	u8 reg = LM93_TEMP_OFFSET_TO_REG(
+			(LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode);
+
+	switch (nr) {
+	case 0:
+		reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f);
+		break;
+	case 1:
+		reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f);
+		break;
+	case 2:
+		reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f);
+		break;
+	case 3:
+	default:
+		reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f);
+		break;
+	}
+
+	return reg;
+}
+
+/*
+ * PWM: 0-255 per sensors documentation
+ * REG: 0-13 as mapped below... right justified
+ */
+enum pwm_freq { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ };
+
+static int lm93_pwm_map[2][16] = {
+	{
+		0x00, /*   0.00% */ 0x40, /*  25.00% */
+		0x50, /*  31.25% */ 0x60, /*  37.50% */
+		0x70, /*  43.75% */ 0x80, /*  50.00% */
+		0x90, /*  56.25% */ 0xa0, /*  62.50% */
+		0xb0, /*  68.75% */ 0xc0, /*  75.00% */
+		0xd0, /*  81.25% */ 0xe0, /*  87.50% */
+		0xf0, /*  93.75% */ 0xff, /* 100.00% */
+		0xff, 0xff, /* 14, 15 are reserved and should never occur */
+	},
+	{
+		0x00, /*   0.00% */ 0x40, /*  25.00% */
+		0x49, /*  28.57% */ 0x52, /*  32.14% */
+		0x5b, /*  35.71% */ 0x64, /*  39.29% */
+		0x6d, /*  42.86% */ 0x76, /*  46.43% */
+		0x80, /*  50.00% */ 0x89, /*  53.57% */
+		0x92, /*  57.14% */ 0xb6, /*  71.43% */
+		0xdb, /*  85.71% */ 0xff, /* 100.00% */
+		0xff, 0xff, /* 14, 15 are reserved and should never occur */
+	},
+};
+
+static int LM93_PWM_FROM_REG(u8 reg, enum pwm_freq freq)
+{
+	return lm93_pwm_map[freq][reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_TO_REG(int pwm, enum pwm_freq freq)
+{
+	int i;
+	for (i = 0; i < 13; i++)
+		if (pwm <= lm93_pwm_map[freq][i])
+			break;
+
+	/* can fall through with i==13 */
+	return (u8)i;
+}
+
+static int LM93_FAN_FROM_REG(u16 regs)
+{
+	const u16 count = le16_to_cpu(regs) >> 2;
+	return count == 0 ? -1 : count == 0x3fff ? 0 : 1350000 / count;
+}
+
+/*
+ * RPM: (82.5 to 1350000)
+ * REG: 14-bits, LE, *left* justified
+ */
+static u16 LM93_FAN_TO_REG(long rpm)
+{
+	u16 count, regs;
+
+	if (rpm == 0) {
+		count = 0x3fff;
+	} else {
+		rpm = clamp_val(rpm, 1, 1000000);
+		count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe);
+	}
+
+	regs = count << 2;
+	return cpu_to_le16(regs);
+}
+
+/*
+ * PWM FREQ: HZ
+ * REG: 0-7 as mapped below
+ */
+static int lm93_pwm_freq_map[8] = {
+	22500, 96, 84, 72, 60, 48, 36, 12
+};
+
+static int LM93_PWM_FREQ_FROM_REG(u8 reg)
+{
+	return lm93_pwm_freq_map[reg & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_FREQ_TO_REG(int freq)
+{
+	int i;
+	for (i = 7; i > 0; i--)
+		if (freq <= lm93_pwm_freq_map[i])
+			break;
+
+	/* can fall through with i==0 */
+	return (u8)i;
+}
+
+/*
+ * TIME: 1/100 seconds
+ * REG: 0-7 as mapped below
+ */
+static int lm93_spinup_time_map[8] = {
+	0, 10, 25, 40, 70, 100, 200, 400,
+};
+
+static int LM93_SPINUP_TIME_FROM_REG(u8 reg)
+{
+	return lm93_spinup_time_map[reg >> 5 & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_SPINUP_TIME_TO_REG(int time)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		if (time <= lm93_spinup_time_map[i])
+			break;
+
+	/* can fall through with i==8 */
+	return (u8)i;
+}
+
+#define LM93_RAMP_MIN 0
+#define LM93_RAMP_MAX 75
+
+static int LM93_RAMP_FROM_REG(u8 reg)
+{
+	return (reg & 0x0f) * 5;
+}
+
+/*
+ * RAMP: 1/100 seconds
+ * REG: 50mS/bit 4-bits right justified
+ */
+static u8 LM93_RAMP_TO_REG(int ramp)
+{
+	ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+	return (u8)((ramp + 2) / 5);
+}
+
+/*
+ * PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
+ * REG: (same)
+ */
+static u8 LM93_PROCHOT_TO_REG(long prochot)
+{
+	prochot = clamp_val(prochot, 0, 255);
+	return (u8)prochot;
+}
+
+/*
+ * PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
+ * REG: 0-9 as mapped below
+ */
+static int lm93_interval_map[10] = {
+	73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
+};
+
+static int LM93_INTERVAL_FROM_REG(u8 reg)
+{
+	return lm93_interval_map[reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_INTERVAL_TO_REG(long interval)
+{
+	int i;
+	for (i = 0; i < 9; i++)
+		if (interval <= lm93_interval_map[i])
+			break;
+
+	/* can fall through with i==9 */
+	return (u8)i;
+}
+
+/*
+ * GPIO: 0-255, GPIO0 is LSB
+ * REG: inverted
+ */
+static unsigned LM93_GPI_FROM_REG(u8 reg)
+{
+	return ~reg & 0xff;
+}
+
+/*
+ * alarm bitmask definitions
+ * The LM93 has nearly 64 bits of error status... I've pared that down to
+ * what I think is a useful subset in order to fit it into 32 bits.
+ *
+ * Especially note that the #VRD_HOT alarms are missing because we provide
+ * that information as values in another sysfs file.
+ *
+ * If libsensors is extended to support 64 bit values, this could be revisited.
+ */
+#define LM93_ALARM_IN1		0x00000001
+#define LM93_ALARM_IN2		0x00000002
+#define LM93_ALARM_IN3		0x00000004
+#define LM93_ALARM_IN4		0x00000008
+#define LM93_ALARM_IN5		0x00000010
+#define LM93_ALARM_IN6		0x00000020
+#define LM93_ALARM_IN7		0x00000040
+#define LM93_ALARM_IN8		0x00000080
+#define LM93_ALARM_IN9		0x00000100
+#define LM93_ALARM_IN10		0x00000200
+#define LM93_ALARM_IN11		0x00000400
+#define LM93_ALARM_IN12		0x00000800
+#define LM93_ALARM_IN13		0x00001000
+#define LM93_ALARM_IN14		0x00002000
+#define LM93_ALARM_IN15		0x00004000
+#define LM93_ALARM_IN16		0x00008000
+#define LM93_ALARM_FAN1		0x00010000
+#define LM93_ALARM_FAN2		0x00020000
+#define LM93_ALARM_FAN3		0x00040000
+#define LM93_ALARM_FAN4		0x00080000
+#define LM93_ALARM_PH1_ERR	0x00100000
+#define LM93_ALARM_PH2_ERR	0x00200000
+#define LM93_ALARM_SCSI1_ERR	0x00400000
+#define LM93_ALARM_SCSI2_ERR	0x00800000
+#define LM93_ALARM_DVDDP1_ERR	0x01000000
+#define LM93_ALARM_DVDDP2_ERR	0x02000000
+#define LM93_ALARM_D1_ERR	0x04000000
+#define LM93_ALARM_D2_ERR	0x08000000
+#define LM93_ALARM_TEMP1	0x10000000
+#define LM93_ALARM_TEMP2	0x20000000
+#define LM93_ALARM_TEMP3	0x40000000
+
+static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1)
+{
+	unsigned result;
+	result  = b1.host_status_2 & 0x3f;
+
+	if (vccp_limit_type[0])
+		result |= (b1.host_status_4 & 0x10) << 2;
+	else
+		result |= b1.host_status_2 & 0x40;
+
+	if (vccp_limit_type[1])
+		result |= (b1.host_status_4 & 0x20) << 2;
+	else
+		result |= b1.host_status_2 & 0x80;
+
+	result |= b1.host_status_3 << 8;
+	result |= (b1.fan_status & 0x0f) << 16;
+	result |= (b1.p1_prochot_status & 0x80) << 13;
+	result |= (b1.p2_prochot_status & 0x80) << 14;
+	result |= (b1.host_status_4 & 0xfc) << 20;
+	result |= (b1.host_status_1 & 0x07) << 28;
+	return result;
+}
+
+#define MAX_RETRIES 5
+
+static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
+{
+	int value, i;
+
+	/* retry in case of read errors */
+	for (i = 1; i <= MAX_RETRIES; i++) {
+		value = i2c_smbus_read_byte_data(client, reg);
+		if (value >= 0) {
+			return value;
+		} else {
+			dev_warn(&client->dev,
+				 "lm93: read byte data failed, address 0x%02x.\n",
+				 reg);
+			mdelay(i + 3);
+		}
+
+	}
+
+	/* <TODO> what to return in case of error? */
+	dev_err(&client->dev, "lm93: All read byte retries failed!!\n");
+	return 0;
+}
+
+static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
+{
+	int result;
+
+	/* <TODO> how to handle write errors? */
+	result = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (result < 0)
+		dev_warn(&client->dev,
+			 "lm93: write byte data failed, 0x%02x at address 0x%02x.\n",
+			 value, reg);
+
+	return result;
+}
+
+static u16 lm93_read_word(struct i2c_client *client, u8 reg)
+{
+	int value, i;
+
+	/* retry in case of read errors */
+	for (i = 1; i <= MAX_RETRIES; i++) {
+		value = i2c_smbus_read_word_data(client, reg);
+		if (value >= 0) {
+			return value;
+		} else {
+			dev_warn(&client->dev,
+				 "lm93: read word data failed, address 0x%02x.\n",
+				 reg);
+			mdelay(i + 3);
+		}
+
+	}
+
+	/* <TODO> what to return in case of error? */
+	dev_err(&client->dev, "lm93: All read word retries failed!!\n");
+	return 0;
+}
+
+static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+	int result;
+
+	/* <TODO> how to handle write errors? */
+	result = i2c_smbus_write_word_data(client, reg, value);
+
+	if (result < 0)
+		dev_warn(&client->dev,
+			 "lm93: write word data failed, 0x%04x at address 0x%02x.\n",
+			 value, reg);
+
+	return result;
+}
+
+static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
+
+/*
+ * read block data into values, retry if not expected length
+ * fbn => index to lm93_block_read_cmds table
+ * (Fixed Block Number - section 14.5.2 of LM93 datasheet)
+ */
+static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
+{
+	int i, result = 0;
+
+	for (i = 1; i <= MAX_RETRIES; i++) {
+		result = i2c_smbus_read_block_data(client,
+			lm93_block_read_cmds[fbn].cmd, lm93_block_buffer);
+
+		if (result == lm93_block_read_cmds[fbn].len) {
+			break;
+		} else {
+			dev_warn(&client->dev,
+				 "lm93: block read data failed, command 0x%02x.\n",
+				 lm93_block_read_cmds[fbn].cmd);
+			mdelay(i + 3);
+		}
+	}
+
+	if (result == lm93_block_read_cmds[fbn].len) {
+		memcpy(values, lm93_block_buffer,
+		       lm93_block_read_cmds[fbn].len);
+	} else {
+		/* <TODO> what to do in case of error? */
+	}
+}
+
+static struct lm93_data *lm93_update_device(struct device *dev)
+{
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	const unsigned long interval = HZ + (HZ / 2);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + interval) ||
+		!data->valid) {
+
+		data->update(data, client);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/* update routine for data that has no corresponding SMBus block command */
+static void lm93_update_client_common(struct lm93_data *data,
+				      struct i2c_client *client)
+{
+	int i;
+	u8 *ptr;
+
+	/* temp1 - temp4: limits */
+	for (i = 0; i < 4; i++) {
+		data->temp_lim[i].min =
+			lm93_read_byte(client, LM93_REG_TEMP_MIN(i));
+		data->temp_lim[i].max =
+			lm93_read_byte(client, LM93_REG_TEMP_MAX(i));
+	}
+
+	/* config register */
+	data->config = lm93_read_byte(client, LM93_REG_CONFIG);
+
+	/* vid1 - vid2: values */
+	for (i = 0; i < 2; i++)
+		data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i));
+
+	/* prochot1 - prochot2: limits */
+	for (i = 0; i < 2; i++)
+		data->prochot_max[i] = lm93_read_byte(client,
+				LM93_REG_PROCHOT_MAX(i));
+
+	/* vccp1 - vccp2: VID relative limits */
+	for (i = 0; i < 2; i++)
+		data->vccp_limits[i] = lm93_read_byte(client,
+				LM93_REG_VCCP_LIMIT_OFF(i));
+
+	/* GPIO input state */
+	data->gpi = lm93_read_byte(client, LM93_REG_GPI);
+
+	/* #PROCHOT override state */
+	data->prochot_override = lm93_read_byte(client,
+			LM93_REG_PROCHOT_OVERRIDE);
+
+	/* #PROCHOT intervals */
+	data->prochot_interval = lm93_read_byte(client,
+			LM93_REG_PROCHOT_INTERVAL);
+
+	/* Fan Boost Temperature registers */
+	for (i = 0; i < 4; i++)
+		data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
+
+	/* Fan Boost Temperature Hyst. registers */
+	data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12);
+	data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34);
+
+	/* Temperature Zone Min. PWM & Hysteresis registers */
+	data->auto_pwm_min_hyst[0] =
+			lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12);
+	data->auto_pwm_min_hyst[1] =
+			lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34);
+
+	/* #PROCHOT & #VRDHOT PWM Ramp Control register */
+	data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+
+	/* misc setup registers */
+	data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1);
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sf_tach_to_pwm = lm93_read_byte(client,
+			LM93_REG_SF_TACH_TO_PWM);
+
+	/* write back alarm values to clear */
+	for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++)
+		lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i));
+}
+
+/* update routine which uses SMBus block data commands */
+static void lm93_update_client_full(struct lm93_data *data,
+				    struct i2c_client *client)
+{
+	dev_dbg(&client->dev, "starting device update (block data enabled)\n");
+
+	/* in1 - in16: values & limits */
+	lm93_read_block(client, 3, (u8 *)(data->block3));
+	lm93_read_block(client, 7, (u8 *)(data->block7));
+
+	/* temp1 - temp4: values */
+	lm93_read_block(client, 2, (u8 *)(data->block2));
+
+	/* prochot1 - prochot2: values */
+	lm93_read_block(client, 4, (u8 *)(data->block4));
+
+	/* fan1 - fan4: values & limits */
+	lm93_read_block(client, 5, (u8 *)(data->block5));
+	lm93_read_block(client, 8, (u8 *)(data->block8));
+
+	/* pmw control registers */
+	lm93_read_block(client, 9, (u8 *)(data->block9));
+
+	/* alarm values */
+	lm93_read_block(client, 1, (u8 *)(&data->block1));
+
+	/* auto/pwm registers */
+	lm93_read_block(client, 10, (u8 *)(&data->block10));
+
+	lm93_update_client_common(data, client);
+}
+
+/* update routine which uses SMBus byte/word data commands only */
+static void lm93_update_client_min(struct lm93_data *data,
+				   struct i2c_client *client)
+{
+	int i, j;
+	u8 *ptr;
+
+	dev_dbg(&client->dev, "starting device update (block data disabled)\n");
+
+	/* in1 - in16: values & limits */
+	for (i = 0; i < 16; i++) {
+		data->block3[i] =
+			lm93_read_byte(client, LM93_REG_IN(i));
+		data->block7[i].min =
+			lm93_read_byte(client, LM93_REG_IN_MIN(i));
+		data->block7[i].max =
+			lm93_read_byte(client, LM93_REG_IN_MAX(i));
+	}
+
+	/* temp1 - temp4: values */
+	for (i = 0; i < 4; i++) {
+		data->block2[i] =
+			lm93_read_byte(client, LM93_REG_TEMP(i));
+	}
+
+	/* prochot1 - prochot2: values */
+	for (i = 0; i < 2; i++) {
+		data->block4[i].cur =
+			lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i));
+		data->block4[i].avg =
+			lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i));
+	}
+
+	/* fan1 - fan4: values & limits */
+	for (i = 0; i < 4; i++) {
+		data->block5[i] =
+			lm93_read_word(client, LM93_REG_FAN(i));
+		data->block8[i] =
+			lm93_read_word(client, LM93_REG_FAN_MIN(i));
+	}
+
+	/* pwm control registers */
+	for (i = 0; i < 2; i++) {
+		for (j = 0; j < 4; j++) {
+			data->block9[i][j] =
+				lm93_read_byte(client, LM93_REG_PWM_CTL(i, j));
+		}
+	}
+
+	/* alarm values */
+	for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) {
+		*(ptr + i) =
+			lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i);
+	}
+
+	/* auto/pwm (base temp) registers */
+	for (i = 0; i < 4; i++) {
+		data->block10.base[i] =
+			lm93_read_byte(client, LM93_REG_TEMP_BASE(i));
+	}
+
+	/* auto/pwm (offset temp) registers */
+	for (i = 0; i < 12; i++) {
+		data->block10.offset[i] =
+			lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i));
+	}
+
+	lm93_update_client_common(data, client);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_in, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_in, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_in, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_in, NULL, 13);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_in, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in, NULL, 15);
+
+static ssize_t show_in_min(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int vccp = nr - 6;
+	long rc, vid;
+
+	if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
+	} else {
+		rc = LM93_IN_FROM_REG(nr, data->block7[nr].min);
+	}
+	return sprintf(buf, "%ld\n", rc);
+}
+
+static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int vccp = nr - 6;
+	long vid;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
+				LM93_IN_REL_TO_REG(val, 0, vid);
+		lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+				data->vccp_limits[vccp]);
+	} else {
+		data->block7[nr].min = LM93_IN_TO_REG(nr, val);
+		lm93_write_byte(client, LM93_REG_IN_MIN(nr),
+				data->block7[nr].min);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 12);
+static SENSOR_DEVICE_ATTR(in14_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 13);
+static SENSOR_DEVICE_ATTR(in15_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 14);
+static SENSOR_DEVICE_ATTR(in16_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 15);
+
+static ssize_t show_in_max(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int vccp = nr - 6;
+	long rc, vid;
+
+	if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp], vid);
+	} else {
+		rc = LM93_IN_FROM_REG(nr, data->block7[nr].max);
+	}
+	return sprintf(buf, "%ld\n", rc);
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int vccp = nr - 6;
+	long vid;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
+				LM93_IN_REL_TO_REG(val, 1, vid);
+		lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+				data->vccp_limits[vccp]);
+	} else {
+		data->block7[nr].max = LM93_IN_TO_REG(nr, val);
+		lm93_write_byte(client, LM93_REG_IN_MAX(nr),
+				data->block7[nr].max);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 12);
+static SENSOR_DEVICE_ATTR(in14_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 13);
+static SENSOR_DEVICE_ATTR(in15_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 14);
+static SENSOR_DEVICE_ATTR(in16_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 15);
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block2[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static ssize_t show_temp_min(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].min));
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 2);
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].max));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 2);
+
+static ssize_t show_temp_auto_base(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block10.base[nr]));
+}
+
+static ssize_t store_temp_auto_base(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->block10.base[nr] = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 2);
+
+static ssize_t show_temp_auto_boost(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->boost[nr]));
+}
+
+static ssize_t store_temp_auto_boost(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->boost[nr] = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 2);
+
+static ssize_t show_temp_auto_boost_hyst(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf, "%d\n",
+		       LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode));
+}
+
+static ssize_t store_temp_auto_boost_hyst(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1);
+	lm93_write_byte(client, LM93_REG_BOOST_HYST(nr),
+			data->boost_hyst[nr/2]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 2);
+
+static ssize_t show_temp_auto_offset(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+	int nr = s_attr->index;
+	int ofs = s_attr->nr;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf, "%d\n",
+	       LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs],
+					      nr, mode));
+}
+
+static ssize_t store_temp_auto_offset(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+	int nr = s_attr->index;
+	int ofs = s_attr->nr;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG(
+			data->block10.offset[ofs], val, nr, 1);
+	lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs),
+			data->block10.offset[ofs]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 2);
+
+static ssize_t show_temp_auto_pwm_min(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	u8 reg, ctl4;
+	struct lm93_data *data = lm93_update_device(dev);
+	reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f;
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf, "%d\n", LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ?
+				LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_temp_auto_pwm_min(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 reg, ctl4;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+	reg = (reg & 0x0f) |
+		LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+				LM93_PWM_MAP_LO_FREQ :
+				LM93_PWM_MAP_HI_FREQ) << 4;
+	data->auto_pwm_min_hyst[nr/2] = reg;
+	lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 2);
+
+static ssize_t show_temp_auto_offset_hyst(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf, "%d\n", LM93_TEMP_OFFSET_FROM_REG(
+					data->auto_pwm_min_hyst[nr / 2], mode));
+}
+
+static ssize_t store_temp_auto_offset_hyst(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	reg = data->auto_pwm_min_hyst[nr/2];
+	reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f);
+	data->auto_pwm_min_hyst[nr/2] = reg;
+	lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 2);
+
+static ssize_t show_fan_input(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
+	int nr = s_attr->index;
+	struct lm93_data *data = lm93_update_device(dev);
+
+	return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block5[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+
+static ssize_t show_fan_min(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+
+	return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block8[nr]));
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->block8[nr] = LM93_FAN_TO_REG(val);
+	lm93_write_word(client, LM93_REG_FAN_MIN(nr), data->block8[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 3);
+
+/*
+ * some tedious bit-twiddling here to deal with the register format:
+ *
+ *	data->sf_tach_to_pwm: (tach to pwm mapping bits)
+ *
+ *		bit |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0
+ *		     T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
+ *
+ *	data->sfc2: (enable bits)
+ *
+ *		bit |  3  |  2  |  1  |  0
+ *		       T4    T3    T2    T1
+ */
+
+static ssize_t show_fan_smart_tach(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	long rc = 0;
+	int mapping;
+
+	/* extract the relevant mapping */
+	mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03;
+
+	/* if there's a mapping and it's enabled */
+	if (mapping && ((data->sfc2 >> nr) & 0x01))
+		rc = mapping;
+	return sprintf(buf, "%ld\n", rc);
+}
+
+/*
+ * helper function - must grab data->update_lock before calling
+ * fan is 0-3, indicating fan1-fan4
+ */
+static void lm93_write_fan_smart_tach(struct i2c_client *client,
+	struct lm93_data *data, int fan, long value)
+{
+	/* insert the new mapping and write it out */
+	data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+	data->sf_tach_to_pwm &= ~(0x3 << fan * 2);
+	data->sf_tach_to_pwm |= value << fan * 2;
+	lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm);
+
+	/* insert the enable bit and write it out */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	if (value)
+		data->sfc2 |= 1 << fan;
+	else
+		data->sfc2 &= ~(1 << fan);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_fan_smart_tach(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	/* sanity test, ignore the write otherwise */
+	if (val <= 2) {
+		/* can't enable if pwm freq is 22.5KHz */
+		if (val) {
+			u8 ctl4 = lm93_read_byte(client,
+				LM93_REG_PWM_CTL(val - 1, LM93_PWM_CTL4));
+			if ((ctl4 & 0x07) == 0)
+				val = 0;
+		}
+		lm93_write_fan_smart_tach(client, data, nr, val);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 0);
+static SENSOR_DEVICE_ATTR(fan2_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 1);
+static SENSOR_DEVICE_ATTR(fan3_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 2);
+static SENSOR_DEVICE_ATTR(fan4_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 3);
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl2, ctl4;
+	long rc;
+
+	ctl2 = data->block9[nr][LM93_PWM_CTL2];
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	if (ctl2 & 0x01) /* show user commanded value if enabled */
+		rc = data->pwm_override[nr];
+	else /* show present h/w value if manual pwm disabled */
+		rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ);
+	return sprintf(buf, "%ld\n", rc);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ctl2, ctl4;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2));
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+	ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4;
+	/* save user commanded value */
+	data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4,
+			(ctl4 & 0x07) ?  LM93_PWM_MAP_LO_FREQ :
+			LM93_PWM_MAP_HI_FREQ);
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+
+static ssize_t show_pwm_enable(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl2;
+	long rc;
+
+	ctl2 = data->block9[nr][LM93_PWM_CTL2];
+	if (ctl2 & 0x01) /* manual override enabled ? */
+		rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1;
+	else
+		rc = 2;
+	return sprintf(buf, "%ld\n", rc);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ctl2;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2));
+
+	switch (val) {
+	case 0:
+		ctl2 |= 0xF1; /* enable manual override, set PWM to max */
+		break;
+	case 1:
+		ctl2 |= 0x01; /* enable manual override */
+		break;
+	case 2:
+		ctl2 &= ~0x01; /* disable manual override */
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+				show_pwm_enable, store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+				show_pwm_enable, store_pwm_enable, 1);
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl4;
+
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf, "%d\n", LM93_PWM_FREQ_FROM_REG(ctl4));
+}
+
+/*
+ * helper function - must grab data->update_lock before calling
+ * pwm is 0-1, indicating pwm1-pwm2
+ * this disables smart tach for all tach channels bound to the given pwm
+ */
+static void lm93_disable_fan_smart_tach(struct i2c_client *client,
+	struct lm93_data *data, int pwm)
+{
+	int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+	int mask;
+
+	/* collapse the mapping into a mask of enable bits */
+	mapping = (mapping >> pwm) & 0x55;
+	mask = mapping & 0x01;
+	mask |= (mapping & 0x04) >> 1;
+	mask |= (mapping & 0x10) >> 2;
+	mask |= (mapping & 0x40) >> 3;
+
+	/* disable smart tach according to the mask */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 &= ~mask;
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ctl4;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+	ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val);
+	data->block9[nr][LM93_PWM_CTL4] = ctl4;
+	/* ctl4 == 0 -> 22.5KHz -> disable smart tach */
+	if (!ctl4)
+		lm93_disable_fan_smart_tach(client, data, nr);
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4), ctl4);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO,
+			  show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IWUSR | S_IRUGO,
+			  show_pwm_freq, store_pwm_freq, 1);
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", data->block9[nr][LM93_PWM_CTL1]);
+}
+
+static ssize_t store_pwm_auto_channels(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255);
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1),
+				data->block9[nr][LM93_PWM_CTL1]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_channels, store_pwm_auto_channels, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_channels, store_pwm_auto_channels, 1);
+
+static ssize_t show_pwm_auto_spinup_min(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl3, ctl4;
+
+	ctl3 = data->block9[nr][LM93_PWM_CTL3];
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf, "%d\n",
+		       LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_pwm_auto_spinup_min(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ctl3, ctl4;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+	ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ :
+			LM93_PWM_MAP_HI_FREQ);
+	data->block9[nr][LM93_PWM_CTL3] = ctl3;
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_min, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_min,
+			  store_pwm_auto_spinup_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_min, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_min,
+			  store_pwm_auto_spinup_min, 1);
+
+static ssize_t show_pwm_auto_spinup_time(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_SPINUP_TIME_FROM_REG(
+				data->block9[nr][LM93_PWM_CTL3]));
+}
+
+static ssize_t store_pwm_auto_spinup_time(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ctl3;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+	ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0);
+	data->block9[nr][LM93_PWM_CTL3] = ctl3;
+	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_time, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_time,
+			  store_pwm_auto_spinup_time, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_time,
+			  store_pwm_auto_spinup_time, 1);
+
+static ssize_t show_pwm_auto_prochot_ramp(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f));
+}
+
+static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ramp;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+	ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0);
+	lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR,
+			show_pwm_auto_prochot_ramp,
+			store_pwm_auto_prochot_ramp);
+
+static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f));
+}
+
+static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 ramp;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+	ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f);
+	lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+	mutex_unlock(&data->update_lock);
+	return 0;
+}
+
+static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR,
+			show_pwm_auto_vrdhot_ramp,
+			store_pwm_auto_vrdhot_ramp);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_VID_FROM_REG(data->vid[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1);
+
+static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", data->block4[nr].cur);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2, S_IRUGO, show_prochot, NULL, 1);
+
+static ssize_t show_prochot_avg(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", data->block4[nr].avg);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2_avg, S_IRUGO, show_prochot_avg, NULL, 1);
+
+static ssize_t show_prochot_max(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", data->prochot_max[nr]);
+}
+
+static ssize_t store_prochot_max(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr),
+			data->prochot_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_max, S_IWUSR | S_IRUGO,
+			  show_prochot_max, store_prochot_max, 0);
+static SENSOR_DEVICE_ATTR(prochot2_max, S_IWUSR | S_IRUGO,
+			  show_prochot_max, store_prochot_max, 1);
+
+static const u8 prochot_override_mask[] = { 0x80, 0x40 };
+
+static ssize_t show_prochot_override(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n",
+		(data->prochot_override & prochot_override_mask[nr]) ? 1 : 0);
+}
+
+static ssize_t store_prochot_override(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->prochot_override |= prochot_override_mask[nr];
+	else
+		data->prochot_override &= (~prochot_override_mask[nr]);
+	lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+			data->prochot_override);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_override, S_IWUSR | S_IRUGO,
+			  show_prochot_override, store_prochot_override, 0);
+static SENSOR_DEVICE_ATTR(prochot2_override, S_IWUSR | S_IRUGO,
+			  show_prochot_override, store_prochot_override, 1);
+
+static ssize_t show_prochot_interval(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 tmp;
+	if (nr == 1)
+		tmp = (data->prochot_interval & 0xf0) >> 4;
+	else
+		tmp = data->prochot_interval & 0x0f;
+	return sprintf(buf, "%d\n", LM93_INTERVAL_FROM_REG(tmp));
+}
+
+static ssize_t store_prochot_interval(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 tmp;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
+	if (nr == 1)
+		tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4);
+	else
+		tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val);
+	data->prochot_interval = tmp;
+	lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO,
+			  show_prochot_interval, store_prochot_interval, 0);
+static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO,
+			  show_prochot_interval, store_prochot_interval, 1);
+
+static ssize_t show_prochot_override_duty_cycle(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", data->prochot_override & 0x0f);
+}
+
+static ssize_t store_prochot_override_duty_cycle(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->prochot_override = (data->prochot_override & 0xf0) |
+					clamp_val(val, 0, 15);
+	lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+			data->prochot_override);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR,
+			show_prochot_override_duty_cycle,
+			store_prochot_override_duty_cycle);
+
+static ssize_t show_prochot_short(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", (data->config & 0x10) ? 1 : 0);
+}
+
+static ssize_t store_prochot_short(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct lm93_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->config |= 0x10;
+	else
+		data->config &= ~0x10;
+	lm93_write_byte(client, LM93_REG_CONFIG, data->config);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR,
+		   show_prochot_short, store_prochot_short);
+
+static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       data->block1.host_status_1 & (1 << (nr + 4)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0);
+static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1);
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_GPI_FROM_REG(data->gpi));
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_ALARMS_FROM_REG(data->block1));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm93_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+	&sensor_dev_attr_in14_input.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	&sensor_dev_attr_in16_input.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,
+	&sensor_dev_attr_in12_min.dev_attr.attr,
+	&sensor_dev_attr_in13_min.dev_attr.attr,
+	&sensor_dev_attr_in14_min.dev_attr.attr,
+	&sensor_dev_attr_in15_min.dev_attr.attr,
+	&sensor_dev_attr_in16_min.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,
+	&sensor_dev_attr_in12_max.dev_attr.attr,
+	&sensor_dev_attr_in13_max.dev_attr.attr,
+	&sensor_dev_attr_in14_max.dev_attr.attr,
+	&sensor_dev_attr_in15_max.dev_attr.attr,
+	&sensor_dev_attr_in16_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan2_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan3_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan4_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
+	&dev_attr_pwm_auto_prochot_ramp.attr,
+	&dev_attr_pwm_auto_vrdhot_ramp.attr,
+	&sensor_dev_attr_cpu0_vid.dev_attr.attr,
+	&sensor_dev_attr_cpu1_vid.dev_attr.attr,
+	&sensor_dev_attr_prochot1.dev_attr.attr,
+	&sensor_dev_attr_prochot2.dev_attr.attr,
+	&sensor_dev_attr_prochot1_avg.dev_attr.attr,
+	&sensor_dev_attr_prochot2_avg.dev_attr.attr,
+	&sensor_dev_attr_prochot1_max.dev_attr.attr,
+	&sensor_dev_attr_prochot2_max.dev_attr.attr,
+	&sensor_dev_attr_prochot1_override.dev_attr.attr,
+	&sensor_dev_attr_prochot2_override.dev_attr.attr,
+	&sensor_dev_attr_prochot1_interval.dev_attr.attr,
+	&sensor_dev_attr_prochot2_interval.dev_attr.attr,
+	&dev_attr_prochot_override_duty_cycle.attr,
+	&dev_attr_prochot_short.attr,
+	&sensor_dev_attr_vrdhot1.dev_attr.attr,
+	&sensor_dev_attr_vrdhot2.dev_attr.attr,
+	&dev_attr_gpio.attr,
+	&dev_attr_alarms.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(lm93);
+
+static void lm93_init_client(struct i2c_client *client)
+{
+	int i;
+	u8 reg;
+
+	/* configure VID pin input thresholds */
+	reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL);
+	lm93_write_byte(client, LM93_REG_GPI_VID_CTL,
+			reg | (vid_agtl ? 0x03 : 0x00));
+
+	if (init) {
+		/* enable #ALERT pin */
+		reg = lm93_read_byte(client, LM93_REG_CONFIG);
+		lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08);
+
+		/* enable ASF mode for BMC status registers */
+		reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL);
+		lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02);
+
+		/* set sleep state to S0 */
+		lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0);
+
+		/* unmask #VRDHOT and dynamic VCCP (if nec) error events */
+		reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK);
+		reg &= ~0x03;
+		reg &= ~(vccp_limit_type[0] ? 0x10 : 0);
+		reg &= ~(vccp_limit_type[1] ? 0x20 : 0);
+		lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg);
+	}
+
+	/* start monitoring */
+	reg = lm93_read_byte(client, LM93_REG_CONFIG);
+	lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01);
+
+	/* spin until ready */
+	for (i = 0; i < 20; i++) {
+		msleep(10);
+		if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80)
+			return;
+	}
+
+	dev_warn(&client->dev,
+		 "timed out waiting for sensor chip to signal ready!\n");
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int mfr, ver;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN))
+		return -ENODEV;
+
+	/* detection */
+	mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+	if (mfr != 0x01) {
+		dev_dbg(&adapter->dev,
+			"detect failed, bad manufacturer id 0x%02x!\n", mfr);
+		return -ENODEV;
+	}
+
+	ver = lm93_read_byte(client, LM93_REG_VER);
+	switch (ver) {
+	case LM93_MFR_ID:
+	case LM93_MFR_ID_PROTOTYPE:
+		name = "lm93";
+		break;
+	case LM94_MFR_ID_2:
+	case LM94_MFR_ID:
+	case LM94_MFR_ID_PROTOTYPE:
+		name = "lm94";
+		break;
+	default:
+		dev_dbg(&adapter->dev,
+			"detect failed, bad version id 0x%02x!\n", ver);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+	dev_dbg(&adapter->dev, "loading %s at %d, 0x%02x\n",
+		client->name, i2c_adapter_id(client->adapter),
+		client->addr);
+
+	return 0;
+}
+
+static int lm93_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct lm93_data *data;
+	struct device *hwmon_dev;
+	int func;
+	void (*update)(struct lm93_data *, struct i2c_client *);
+
+	/* choose update routine based on bus capabilities */
+	func = i2c_get_functionality(client->adapter);
+	if (((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+			(!disable_block)) {
+		dev_dbg(dev, "using SMBus block data transactions\n");
+		update = lm93_update_client_full;
+	} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+		dev_dbg(dev, "disabled SMBus block data transactions\n");
+		update = lm93_update_client_min;
+	} else {
+		dev_dbg(dev, "detect failed, smbus byte and/or word data not supported!\n");
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct lm93_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* housekeeping */
+	data->client = client;
+	data->update = update;
+	mutex_init(&data->update_lock);
+
+	/* initialize the chip */
+	lm93_init_client(client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   lm93_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id lm93_id[] = {
+	{ "lm93", 0 },
+	{ "lm94", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm93_id);
+
+static struct i2c_driver lm93_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm93",
+	},
+	.probe		= lm93_probe,
+	.id_table	= lm93_id,
+	.detect		= lm93_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm93_driver);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
+		"Hans J. Koch <hjk@hansjkoch.de>");
+MODULE_DESCRIPTION("LM93 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c
new file mode 100644
index 0000000..8796de3
--- /dev/null
+++ b/drivers/hwmon/lm95234.c
@@ -0,0 +1,768 @@
+/*
+ * Driver for Texas Instruments / National Semiconductor LM95234
+ *
+ * Copyright (c) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from lm95241.c
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+#define DRVNAME "lm95234"
+
+enum chips { lm95233, lm95234 };
+
+static const unsigned short normal_i2c[] = {
+	0x18, 0x2a, 0x2b, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* LM95234 registers */
+#define LM95234_REG_MAN_ID		0xFE
+#define LM95234_REG_CHIP_ID		0xFF
+#define LM95234_REG_STATUS		0x02
+#define LM95234_REG_CONFIG		0x03
+#define LM95234_REG_CONVRATE		0x04
+#define LM95234_REG_STS_FAULT		0x07
+#define LM95234_REG_STS_TCRIT1		0x08
+#define LM95234_REG_STS_TCRIT2		0x09
+#define LM95234_REG_TEMPH(x)		((x) + 0x10)
+#define LM95234_REG_TEMPL(x)		((x) + 0x20)
+#define LM95234_REG_UTEMPH(x)		((x) + 0x19)	/* Remote only */
+#define LM95234_REG_UTEMPL(x)		((x) + 0x29)
+#define LM95234_REG_REM_MODEL		0x30
+#define LM95234_REG_REM_MODEL_STS	0x38
+#define LM95234_REG_OFFSET(x)		((x) + 0x31)	/* Remote only */
+#define LM95234_REG_TCRIT1(x)		((x) + 0x40)
+#define LM95234_REG_TCRIT2(x)		((x) + 0x49)	/* Remote channel 1,2 */
+#define LM95234_REG_TCRIT_HYST		0x5a
+
+#define NATSEMI_MAN_ID			0x01
+#define LM95233_CHIP_ID			0x89
+#define LM95234_CHIP_ID			0x79
+
+/* Client data (each client gets its own) */
+struct lm95234_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	unsigned long last_updated, interval;	/* in jiffies */
+	bool valid;		/* false until following fields are valid */
+	/* registers values */
+	int temp[5];		/* temperature (signed) */
+	u32 status;		/* fault/alarm status */
+	u8 tcrit1[5];		/* critical temperature limit */
+	u8 tcrit2[2];		/* high temperature limit */
+	s8 toffset[4];		/* remote temperature offset */
+	u8 thyst;		/* common hysteresis */
+
+	u8 sensor_type;		/* temperature sensor type */
+};
+
+static int lm95234_read_temp(struct i2c_client *client, int index, int *t)
+{
+	int val;
+	u16 temp = 0;
+
+	if (index) {
+		val = i2c_smbus_read_byte_data(client,
+					       LM95234_REG_UTEMPH(index - 1));
+		if (val < 0)
+			return val;
+		temp = val << 8;
+		val = i2c_smbus_read_byte_data(client,
+					       LM95234_REG_UTEMPL(index - 1));
+		if (val < 0)
+			return val;
+		temp |= val;
+		*t = temp;
+	}
+	/*
+	 * Read signed temperature if unsigned temperature is 0,
+	 * or if this is the local sensor.
+	 */
+	if (!temp) {
+		val = i2c_smbus_read_byte_data(client,
+					       LM95234_REG_TEMPH(index));
+		if (val < 0)
+			return val;
+		temp = val << 8;
+		val = i2c_smbus_read_byte_data(client,
+					       LM95234_REG_TEMPL(index));
+		if (val < 0)
+			return val;
+		temp |= val;
+		*t = (s16)temp;
+	}
+	return 0;
+}
+
+static u16 update_intervals[] = { 143, 364, 1000, 2500 };
+
+/* Fill value cache. Must be called with update lock held. */
+
+static int lm95234_fill_cache(struct lm95234_data *data,
+			      struct i2c_client *client)
+{
+	int i, ret;
+
+	ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+	if (ret < 0)
+		return ret;
+
+	data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
+
+	for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
+		if (ret < 0)
+			return ret;
+		data->tcrit1[i] = ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
+		if (ret < 0)
+			return ret;
+		data->tcrit2[i] = ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
+		if (ret < 0)
+			return ret;
+		data->toffset[i] = ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
+	if (ret < 0)
+		return ret;
+	data->thyst = ret;
+
+	ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+	if (ret < 0)
+		return ret;
+	data->sensor_type = ret;
+
+	return 0;
+}
+
+static int lm95234_update_device(struct lm95234_data *data)
+{
+	struct i2c_client *client = data->client;
+	int ret;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + data->interval) ||
+	    !data->valid) {
+		int i;
+
+		if (!data->valid) {
+			ret = lm95234_fill_cache(data, client);
+			if (ret < 0)
+				goto abort;
+		}
+
+		data->valid = false;
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			ret = lm95234_read_temp(client, i, &data->temp[i]);
+			if (ret < 0)
+				goto abort;
+		}
+
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
+		if (ret < 0)
+			goto abort;
+		data->status = ret;
+
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
+		if (ret < 0)
+			goto abort;
+		data->status |= ret << 8;
+
+		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
+		if (ret < 0)
+			goto abort;
+		data->status |= ret << 16;
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+	ret = 0;
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d\n",
+		       DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	u32 mask = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%u", !!(data->status & mask));
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	u8 mask = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u8 mask = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val != 1 && val != 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (val == 1)
+		data->sensor_type |= mask;
+	else
+		data->sensor_type &= ~mask;
+	data->valid = false;
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_REM_MODEL,
+				  data->sensor_type);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%u", data->tcrit2[index] * 1000);
+}
+
+static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	long val;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
+
+	mutex_lock(&data->update_lock);
+	data->tcrit2[index] = val;
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT2(index), val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_tcrit2_hyst(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	/* Result can be negative, so be careful with unsigned operands */
+	return sprintf(buf, "%d",
+		       ((int)data->tcrit2[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u", data->tcrit1[index] * 1000);
+}
+
+static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+	long val;
+
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->tcrit1[index] = val;
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT1(index), val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_tcrit1_hyst(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	/* Result can be negative, so be careful with unsigned operands */
+	return sprintf(buf, "%d",
+		       ((int)data->tcrit1[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t set_tcrit1_hyst(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+	long val;
+
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	val = DIV_ROUND_CLOSEST(val, 1000);
+	val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
+
+	mutex_lock(&data->update_lock);
+	data->thyst = val;
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT_HYST, val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_offset(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d", data->toffset[index] * 500);
+}
+
+static ssize_t set_offset(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int ret = lm95234_update_device(data);
+	long val;
+
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	/* Accuracy is 1/2 degrees C */
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
+
+	mutex_lock(&data->update_lock);
+	data->toffset[index] = val;
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_OFFSET(index), val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int ret = lm95234_update_device(data);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%lu\n",
+		       DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct lm95234_data *data = dev_get_drvdata(dev);
+	int ret = lm95234_update_device(data);
+	unsigned long val;
+	u8 regval;
+
+	if (ret)
+		return ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	for (regval = 0; regval < 3; regval++) {
+		if (val <= update_intervals[regval])
+			break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->interval = msecs_to_jiffies(update_intervals[regval]);
+	i2c_smbus_write_byte_data(data->client, LM95234_REG_CONVRATE, regval);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+			  BIT(0) | BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL,
+			  BIT(2) | BIT(3));
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL,
+			  BIT(4) | BIT(5));
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL,
+			  BIT(6) | BIT(7));
+
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  BIT(2));
+static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  BIT(3));
+static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  BIT(4));
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1,
+			  set_tcrit1, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2,
+			  set_tcrit2, 0);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2,
+			  set_tcrit2, 1);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1,
+			  set_tcrit1, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1,
+			  set_tcrit1, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst,
+			  set_tcrit1_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(0 + 8));
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(1 + 16));
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(2 + 16));
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(3 + 8));
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(4 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+			  set_tcrit1, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+			  set_tcrit1, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(1 + 8));
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
+			  BIT(2 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset,
+			  set_offset, 0);
+static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset,
+			  set_offset, 1);
+static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset,
+			  set_offset, 2);
+static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
+			  set_offset, 3);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+		   set_interval);
+
+static struct attribute *lm95234_common_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+
+static const struct attribute_group lm95234_common_group = {
+	.attrs = lm95234_common_attrs,
+};
+
+static struct attribute *lm95234_attrs[] = {
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp5_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_type.dev_attr.attr,
+	&sensor_dev_attr_temp5_type.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_offset.dev_attr.attr,
+	&sensor_dev_attr_temp5_offset.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm95234_group = {
+	.attrs = lm95234_attrs,
+};
+
+static int lm95234_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	u8 config_mask, model_mask;
+	int mfg_id, chip_id, val;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
+	if (mfg_id != NATSEMI_MAN_ID)
+		return -ENODEV;
+
+	chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
+	switch (chip_id) {
+	case LM95233_CHIP_ID:
+		if (address != 0x18 && address != 0x2a && address != 0x2b)
+			return -ENODEV;
+		config_mask = 0xbf;
+		model_mask = 0xf9;
+		name = "lm95233";
+		break;
+	case LM95234_CHIP_ID:
+		if (address != 0x18 && address != 0x4d && address != 0x4e)
+			return -ENODEV;
+		config_mask = 0xbc;
+		model_mask = 0xe1;
+		name = "lm95234";
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
+	if (val & 0x30)
+		return -ENODEV;
+
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+	if (val & config_mask)
+		return -ENODEV;
+
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+	if (val & 0xfc)
+		return -ENODEV;
+
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+	if (val & model_mask)
+		return -ENODEV;
+
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+	if (val & model_mask)
+		return -ENODEV;
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+	return 0;
+}
+
+static int lm95234_init_client(struct i2c_client *client)
+{
+	int val, model;
+
+	/* start conversion if necessary */
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+	if (val < 0)
+		return val;
+	if (val & 0x40)
+		i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
+					  val & ~0x40);
+
+	/* If diode type status reports an error, try to fix it */
+	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+	if (val < 0)
+		return val;
+	model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+	if (model < 0)
+		return model;
+	if (model & val) {
+		dev_notice(&client->dev,
+			   "Fixing remote diode type misconfiguration (0x%x)\n",
+			   val);
+		i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
+					  model & ~val);
+	}
+	return 0;
+}
+
+static int lm95234_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct lm95234_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM95234 chip */
+	err = lm95234_init_client(client);
+	if (err < 0)
+		return err;
+
+	data->groups[0] = &lm95234_common_group;
+	if (id->driver_data == lm95234)
+		data->groups[1] = &lm95234_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95234_id[] = {
+	{ "lm95233", lm95233 },
+	{ "lm95234", lm95234 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm95234_id);
+
+static struct i2c_driver lm95234_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= lm95234_probe,
+	.id_table	= lm95234_id,
+	.detect		= lm95234_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm95234_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LM95233/LM95234 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
new file mode 100644
index 0000000..cdf19ad
--- /dev/null
+++ b/drivers/hwmon/lm95241.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
+ *
+ * The LM95241 is a sensor chip made by National Semiconductors.
+ * It reports up to three temperatures (its own plus up to two external ones).
+ * Complete datasheet can be obtained from National's website at:
+ *   http://www.national.com/ds.cgi/LM/LM95241.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>
+
+#define DEVNAME "lm95241"
+
+static const unsigned short normal_i2c[] = {
+	0x19, 0x2a, 0x2b, I2C_CLIENT_END };
+
+/* LM95241 registers */
+#define LM95241_REG_R_MAN_ID		0xFE
+#define LM95241_REG_R_CHIP_ID		0xFF
+#define LM95241_REG_R_STATUS		0x02
+#define LM95241_REG_RW_CONFIG		0x03
+#define LM95241_REG_RW_REM_FILTER	0x06
+#define LM95241_REG_RW_TRUTHERM		0x07
+#define LM95241_REG_W_ONE_SHOT		0x0F
+#define LM95241_REG_R_LOCAL_TEMPH	0x10
+#define LM95241_REG_R_REMOTE1_TEMPH	0x11
+#define LM95241_REG_R_REMOTE2_TEMPH	0x12
+#define LM95241_REG_R_LOCAL_TEMPL	0x20
+#define LM95241_REG_R_REMOTE1_TEMPL	0x21
+#define LM95241_REG_R_REMOTE2_TEMPL	0x22
+#define LM95241_REG_RW_REMOTE_MODEL	0x30
+
+/* LM95241 specific bitfields */
+#define CFG_STOP 0x40
+#define CFG_CR0076 0x00
+#define CFG_CR0182 0x10
+#define CFG_CR1000 0x20
+#define CFG_CR2700 0x30
+#define R1MS_SHIFT 0
+#define R2MS_SHIFT 2
+#define R1MS_MASK (0x01 << (R1MS_SHIFT))
+#define R2MS_MASK (0x01 << (R2MS_SHIFT))
+#define R1DF_SHIFT 1
+#define R2DF_SHIFT 2
+#define R1DF_MASK (0x01 << (R1DF_SHIFT))
+#define R2DF_MASK (0x01 << (R2DF_SHIFT))
+#define R1FE_MASK 0x01
+#define R2FE_MASK 0x05
+#define TT1_SHIFT 0
+#define TT2_SHIFT 4
+#define TT_OFF 0
+#define TT_ON 1
+#define TT_MASK 7
+#define NATSEMI_MAN_ID	0x01
+#define LM95231_CHIP_ID	0xA1
+#define LM95241_CHIP_ID	0xA4
+
+static const u8 lm95241_reg_address[] = {
+	LM95241_REG_R_LOCAL_TEMPH,
+	LM95241_REG_R_LOCAL_TEMPL,
+	LM95241_REG_R_REMOTE1_TEMPH,
+	LM95241_REG_R_REMOTE1_TEMPL,
+	LM95241_REG_R_REMOTE2_TEMPH,
+	LM95241_REG_R_REMOTE2_TEMPL
+};
+
+/* Client data (each client gets its own) */
+struct lm95241_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	unsigned long last_updated, interval;	/* in jiffies */
+	char valid;		/* zero until following fields are valid */
+	/* registers values */
+	u8 temp[ARRAY_SIZE(lm95241_reg_address)];
+	u8 config, model, trutherm;
+};
+
+/* Conversions */
+static int temp_from_reg_signed(u8 val_h, u8 val_l)
+{
+	s16 val_hl = (val_h << 8) | val_l;
+	return val_hl * 1000 / 256;
+}
+
+static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
+{
+	u16 val_hl = (val_h << 8) | val_l;
+	return val_hl * 1000 / 256;
+}
+
+static struct lm95241_data *lm95241_update_device(struct device *dev)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + data->interval) ||
+	    !data->valid) {
+		int i;
+
+		dev_dbg(dev, "Updating lm95241 data.\n");
+		for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
+			data->temp[i]
+			  = i2c_smbus_read_byte_data(client,
+						     lm95241_reg_address[i]);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* Sysfs stuff */
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct lm95241_data *data = lm95241_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+			index == 0 || (data->config & (1 << (index / 2))) ?
+		temp_from_reg_signed(data->temp[index], data->temp[index + 1]) :
+		temp_from_reg_unsigned(data->temp[index],
+				       data->temp[index + 1]));
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1,
+		data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int shift;
+	u8 mask = to_sensor_dev_attr(attr)->index;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val != 1 && val != 2)
+		return -EINVAL;
+
+	shift = mask == R1MS_MASK ? TT1_SHIFT : TT2_SHIFT;
+
+	mutex_lock(&data->update_lock);
+
+	data->trutherm &= ~(TT_MASK << shift);
+	if (val == 1) {
+		data->model |= mask;
+		data->trutherm |= (TT_ON << shift);
+	} else {
+		data->model &= ~mask;
+		data->trutherm |= (TT_OFF << shift);
+	}
+	data->valid = 0;
+
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+				  data->model);
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+				  data->trutherm);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_min(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1,
+			data->config & to_sensor_dev_attr(attr)->index ?
+			"-127000\n" : "0\n");
+}
+
+static ssize_t set_min(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val < -128000)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	if (val < 0)
+		data->config |= to_sensor_dev_attr(attr)->index;
+	else
+		data->config &= ~to_sensor_dev_attr(attr)->index;
+	data->valid = 0;
+
+	i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+				  data->config);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_max(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1,
+			data->config & to_sensor_dev_attr(attr)->index ?
+			"127000\n" : "255000\n");
+}
+
+static ssize_t set_max(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val >= 256000)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	if (val <= 127000)
+		data->config |= to_sensor_dev_attr(attr)->index;
+	else
+		data->config &= ~to_sensor_dev_attr(attr)->index;
+	data->valid = 0;
+
+	i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+				  data->config);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct lm95241_data *data = lm95241_update_device(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval
+			/ HZ);
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct lm95241_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	data->interval = val * HZ / 1000;
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  R1MS_MASK);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+			  R2MS_MASK);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min,
+			  R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min,
+			  R2DF_MASK);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max,
+			  R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
+			  R2DF_MASK);
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+		   set_interval);
+
+static struct attribute *lm95241_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm95241);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm95241_detect(struct i2c_client *new_client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	const char *name;
+	int mfg_id, chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	mfg_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID);
+	if (mfg_id != NATSEMI_MAN_ID)
+		return -ENODEV;
+
+	chip_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID);
+	switch (chip_id) {
+	case LM95231_CHIP_ID:
+		name = "lm95231";
+		break;
+	case LM95241_CHIP_ID:
+		name = "lm95241";
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	/* Fill the i2c board info */
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+	return 0;
+}
+
+static void lm95241_init_client(struct i2c_client *client,
+				struct lm95241_data *data)
+{
+	data->interval = HZ;	/* 1 sec default */
+	data->config = CFG_CR0076;
+	data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
+
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
+				  R1FE_MASK | R2FE_MASK);
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+				  data->trutherm);
+	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+				  data->model);
+}
+
+static int lm95241_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct lm95241_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM95241 chip */
+	lm95241_init_client(client, data);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   lm95241_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95241_id[] = {
+	{ "lm95231", 0 },
+	{ "lm95241", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm95241_id);
+
+static struct i2c_driver lm95241_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= DEVNAME,
+	},
+	.probe		= lm95241_probe,
+	.id_table	= lm95241_id,
+	.detect		= lm95241_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm95241_driver);
+
+MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
+MODULE_DESCRIPTION("LM95241 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
new file mode 100644
index 0000000..e7aef45
--- /dev/null
+++ b/drivers/hwmon/lm95245.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
+ *
+ * The LM95245 is a sensor chip made by TI / National Semiconductor.
+ * It reports up to two temperatures (its own plus an external one).
+ *
+ * This driver is based on lm95241.c
+ *
+ * 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[] = {
+	0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
+
+/* LM95245 registers */
+/* general registers */
+#define LM95245_REG_RW_CONFIG1		0x03
+#define LM95245_REG_RW_CONVERS_RATE	0x04
+#define LM95245_REG_W_ONE_SHOT		0x0F
+
+/* diode configuration */
+#define LM95245_REG_RW_CONFIG2		0xBF
+#define LM95245_REG_RW_REMOTE_OFFH	0x11
+#define LM95245_REG_RW_REMOTE_OFFL	0x12
+
+/* status registers */
+#define LM95245_REG_R_STATUS1		0x02
+#define LM95245_REG_R_STATUS2		0x33
+
+/* limit registers */
+#define LM95245_REG_RW_REMOTE_OS_LIMIT		0x07
+#define LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT	0x20
+#define LM95245_REG_RW_REMOTE_TCRIT_LIMIT	0x19
+#define LM95245_REG_RW_COMMON_HYSTERESIS	0x21
+
+/* temperature signed */
+#define LM95245_REG_R_LOCAL_TEMPH_S	0x00
+#define LM95245_REG_R_LOCAL_TEMPL_S	0x30
+#define LM95245_REG_R_REMOTE_TEMPH_S	0x01
+#define LM95245_REG_R_REMOTE_TEMPL_S	0x10
+/* temperature unsigned */
+#define LM95245_REG_R_REMOTE_TEMPH_U	0x31
+#define LM95245_REG_R_REMOTE_TEMPL_U	0x32
+
+/* id registers */
+#define LM95245_REG_R_MAN_ID		0xFE
+#define LM95245_REG_R_CHIP_ID		0xFF
+
+/* LM95245 specific bitfields */
+#define CFG_STOP		0x40
+#define CFG_REMOTE_TCRIT_MASK	0x10
+#define CFG_REMOTE_OS_MASK	0x08
+#define CFG_LOCAL_TCRIT_MASK	0x04
+#define CFG_LOCAL_OS_MASK	0x02
+
+#define CFG2_OS_A0		0x40
+#define CFG2_DIODE_FAULT_OS	0x20
+#define CFG2_DIODE_FAULT_TCRIT	0x10
+#define CFG2_REMOTE_TT		0x08
+#define CFG2_REMOTE_FILTER_DIS	0x00
+#define CFG2_REMOTE_FILTER_EN	0x06
+
+/* conversation rate in ms */
+#define RATE_CR0063	0x00
+#define RATE_CR0364	0x01
+#define RATE_CR1000	0x02
+#define RATE_CR2500	0x03
+
+#define STATUS1_DIODE_FAULT	0x04
+#define STATUS1_RTCRIT		0x02
+#define STATUS1_LOC		0x01
+
+#define MANUFACTURER_ID		0x01
+#define LM95235_REVISION	0xB1
+#define LM95245_REVISION	0xB3
+
+static const u8 lm95245_reg_address[] = {
+	LM95245_REG_R_LOCAL_TEMPH_S,
+	LM95245_REG_R_LOCAL_TEMPL_S,
+	LM95245_REG_R_REMOTE_TEMPH_S,
+	LM95245_REG_R_REMOTE_TEMPL_S,
+	LM95245_REG_R_REMOTE_TEMPH_U,
+	LM95245_REG_R_REMOTE_TEMPL_U,
+	LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
+	LM95245_REG_RW_REMOTE_TCRIT_LIMIT,
+	LM95245_REG_RW_COMMON_HYSTERESIS,
+	LM95245_REG_R_STATUS1,
+};
+
+/* Client data (each client gets its own) */
+struct lm95245_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	unsigned long last_updated;	/* in jiffies */
+	unsigned long interval;	/* in msecs */
+	bool valid;		/* zero until following fields are valid */
+	/* registers values */
+	u8 regs[ARRAY_SIZE(lm95245_reg_address)];
+	u8 config1, config2;
+};
+
+/* Conversions */
+static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
+{
+	return val_h * 1000 + val_l * 1000 / 256;
+}
+
+static int temp_from_reg_signed(u8 val_h, u8 val_l)
+{
+	if (val_h & 0x80)
+		return (val_h - 0x100) * 1000;
+	return temp_from_reg_unsigned(val_h, val_l);
+}
+
+static struct lm95245_data *lm95245_update_device(struct device *dev)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated
+		+ msecs_to_jiffies(data->interval)) || !data->valid) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
+			data->regs[i]
+			  = i2c_smbus_read_byte_data(client,
+						     lm95245_reg_address[i]);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static unsigned long lm95245_read_conversion_rate(struct i2c_client *client)
+{
+	int rate;
+	unsigned long interval;
+
+	rate = i2c_smbus_read_byte_data(client, LM95245_REG_RW_CONVERS_RATE);
+
+	switch (rate) {
+	case RATE_CR0063:
+		interval = 63;
+		break;
+	case RATE_CR0364:
+		interval = 364;
+		break;
+	case RATE_CR1000:
+		interval = 1000;
+		break;
+	case RATE_CR2500:
+	default:
+		interval = 2500;
+		break;
+	}
+
+	return interval;
+}
+
+static unsigned long lm95245_set_conversion_rate(struct i2c_client *client,
+			unsigned long interval)
+{
+	int rate;
+
+	if (interval <= 63) {
+		interval = 63;
+		rate = RATE_CR0063;
+	} else if (interval <= 364) {
+		interval = 364;
+		rate = RATE_CR0364;
+	} else if (interval <= 1000) {
+		interval = 1000;
+		rate = RATE_CR1000;
+	} else {
+		interval = 2500;
+		rate = RATE_CR2500;
+	}
+
+	i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONVERS_RATE, rate);
+
+	return interval;
+}
+
+/* Sysfs stuff */
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct lm95245_data *data = lm95245_update_device(dev);
+	int temp;
+	int index = to_sensor_dev_attr(attr)->index;
+
+	/*
+	 * Index 0 (Local temp) is always signed
+	 * Index 2 (Remote temp) has both signed and unsigned data
+	 * use signed calculation for remote if signed bit is set
+	 */
+	if (index == 0 || data->regs[index] & 0x80)
+		temp = temp_from_reg_signed(data->regs[index],
+			    data->regs[index + 1]);
+	else
+		temp = temp_from_reg_unsigned(data->regs[index + 2],
+			    data->regs[index + 3]);
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n", temp);
+}
+
+static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95245_data *data = lm95245_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+			data->regs[index] * 1000);
+}
+
+static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = data->client;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	val /= 1000;
+
+	val = clamp_val(val, 0, (index == 6 ? 127 : 255));
+
+	mutex_lock(&data->update_lock);
+
+	data->valid = 0;
+
+	i2c_smbus_write_byte_data(client, lm95245_reg_address[index], val);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct lm95245_data *data = lm95245_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	int hyst = data->regs[index] - data->regs[8];
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000);
+}
+
+static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int hyst, limit;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]);
+	hyst = limit - val / 1000;
+	hyst = clamp_val(hyst, 0, 31);
+	data->regs[8] = hyst;
+
+	/* shared crit hysteresis */
+	i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
+		hyst);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1,
+		data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val != 1 && val != 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	if (val == 1)
+		data->config2 |= CFG2_REMOTE_TT;
+	else
+		data->config2 &= ~CFG2_REMOTE_TT;
+
+	data->valid = 0;
+
+	i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG2,
+				  data->config2);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct lm95245_data *data = lm95245_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+			!!(data->regs[9] & index));
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct lm95245_data *data = lm95245_update_device(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1, "%lu\n", data->interval);
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct lm95245_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	data->interval = lm95245_set_conversion_rate(client, val);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
+		set_limit, 6);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst,
+		set_crit_hyst, 6);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+		STATUS1_LOC);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
+		set_limit, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+		STATUS1_RTCRIT);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
+		set_type, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+		STATUS1_DIODE_FAULT);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+		set_interval);
+
+static struct attribute *lm95245_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&dev_attr_update_interval.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(lm95245);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm95245_detect(struct i2c_client *new_client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+	int address = new_client->addr;
+	const char *name;
+	int rev, id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	id = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID);
+	if (id != MANUFACTURER_ID)
+		return -ENODEV;
+
+	rev = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID);
+	switch (rev) {
+	case LM95235_REVISION:
+		if (address != 0x18 && address != 0x29 && address != 0x4c)
+			return -ENODEV;
+		name = "lm95235";
+		break;
+	case LM95245_REVISION:
+		name = "lm95245";
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+	return 0;
+}
+
+static void lm95245_init_client(struct i2c_client *client,
+				struct lm95245_data *data)
+{
+	data->interval = lm95245_read_conversion_rate(client);
+
+	data->config1 = i2c_smbus_read_byte_data(client,
+		LM95245_REG_RW_CONFIG1);
+	data->config2 = i2c_smbus_read_byte_data(client,
+		LM95245_REG_RW_CONFIG2);
+
+	if (data->config1 & CFG_STOP) {
+		/* Clear the standby bit */
+		data->config1 &= ~CFG_STOP;
+		i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG1,
+			data->config1);
+	}
+}
+
+static int lm95245_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct lm95245_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LM95245 chip */
+	lm95245_init_client(client, data);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   lm95245_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95245_id[] = {
+	{ "lm95235", 0 },
+	{ "lm95245", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm95245_id);
+
+static struct i2c_driver lm95245_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm95245",
+	},
+	.probe		= lm95245_probe,
+	.id_table	= lm95245_id,
+	.detect		= lm95245_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(lm95245_driver);
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("LM95235/LM95245 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
new file mode 100644
index 0000000..1b92e4f
--- /dev/null
+++ b/drivers/hwmon/ltc2945.c
@@ -0,0 +1,519 @@
+/*
+ * Driver for Linear Technology LTC2945 I2C Power Monitor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC2945_CONTROL			0x00
+#define LTC2945_ALERT			0x01
+#define LTC2945_STATUS			0x02
+#define LTC2945_FAULT			0x03
+#define LTC2945_POWER_H			0x05
+#define LTC2945_MAX_POWER_H		0x08
+#define LTC2945_MIN_POWER_H		0x0b
+#define LTC2945_MAX_POWER_THRES_H	0x0e
+#define LTC2945_MIN_POWER_THRES_H	0x11
+#define LTC2945_SENSE_H			0x14
+#define LTC2945_MAX_SENSE_H		0x16
+#define LTC2945_MIN_SENSE_H		0x18
+#define LTC2945_MAX_SENSE_THRES_H	0x1a
+#define LTC2945_MIN_SENSE_THRES_H	0x1c
+#define LTC2945_VIN_H			0x1e
+#define LTC2945_MAX_VIN_H		0x20
+#define LTC2945_MIN_VIN_H		0x22
+#define LTC2945_MAX_VIN_THRES_H		0x24
+#define LTC2945_MIN_VIN_THRES_H		0x26
+#define LTC2945_ADIN_H			0x28
+#define LTC2945_MAX_ADIN_H		0x2a
+#define LTC2945_MIN_ADIN_H		0x2c
+#define LTC2945_MAX_ADIN_THRES_H	0x2e
+#define LTC2945_MIN_ADIN_THRES_H	0x30
+#define LTC2945_MIN_ADIN_THRES_L	0x31
+
+/* Fault register bits */
+
+#define FAULT_ADIN_UV		(1 << 0)
+#define FAULT_ADIN_OV		(1 << 1)
+#define FAULT_VIN_UV		(1 << 2)
+#define FAULT_VIN_OV		(1 << 3)
+#define FAULT_SENSE_UV		(1 << 4)
+#define FAULT_SENSE_OV		(1 << 5)
+#define FAULT_POWER_UV		(1 << 6)
+#define FAULT_POWER_OV		(1 << 7)
+
+/* Control register bits */
+
+#define CONTROL_MULT_SELECT	(1 << 0)
+#define CONTROL_TEST_MODE	(1 << 4)
+
+static inline bool is_power_reg(u8 reg)
+{
+	return reg < LTC2945_SENSE_H;
+}
+
+/* Return the value from the given register in uW, mV, or mA */
+static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int control;
+	u8 buf[3];
+	long long val;
+	int ret;
+
+	ret = regmap_bulk_read(regmap, reg, buf,
+			       is_power_reg(reg) ? 3 : 2);
+	if (ret < 0)
+		return ret;
+
+	if (is_power_reg(reg)) {
+		/* power */
+		val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+	} else {
+		/* current, voltage */
+		val = (buf[0] << 4) + (buf[1] >> 4);
+	}
+
+	switch (reg) {
+	case LTC2945_POWER_H:
+	case LTC2945_MAX_POWER_H:
+	case LTC2945_MIN_POWER_H:
+	case LTC2945_MAX_POWER_THRES_H:
+	case LTC2945_MIN_POWER_THRES_H:
+		/*
+		 * Convert to uW by assuming current is measured with
+		 * an 1mOhm sense resistor, similar to current
+		 * measurements.
+		 * Control register bit 0 selects if voltage at SENSE+/VDD
+		 * or voltage at ADIN is used to measure power.
+		 */
+		ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+		if (ret < 0)
+			return ret;
+		if (control & CONTROL_MULT_SELECT) {
+			/* 25 mV * 25 uV = 0.625 uV resolution. */
+			val *= 625LL;
+		} else {
+			/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
+			val = (val * 25LL) >> 1;
+		}
+		break;
+	case LTC2945_VIN_H:
+	case LTC2945_MAX_VIN_H:
+	case LTC2945_MIN_VIN_H:
+	case LTC2945_MAX_VIN_THRES_H:
+	case LTC2945_MIN_VIN_THRES_H:
+		/* 25 mV resolution. Convert to mV. */
+		val *= 25;
+		break;
+	case LTC2945_ADIN_H:
+	case LTC2945_MAX_ADIN_H:
+	case LTC2945_MIN_ADIN_THRES_H:
+	case LTC2945_MAX_ADIN_THRES_H:
+	case LTC2945_MIN_ADIN_H:
+		/* 0.5mV resolution. Convert to mV. */
+		val = val >> 1;
+		break;
+	case LTC2945_SENSE_H:
+	case LTC2945_MAX_SENSE_H:
+	case LTC2945_MIN_SENSE_H:
+	case LTC2945_MAX_SENSE_THRES_H:
+	case LTC2945_MIN_SENSE_THRES_H:
+		/*
+		 * 25 uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val *= 25;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return val;
+}
+
+static int ltc2945_val_to_reg(struct device *dev, u8 reg,
+			      unsigned long val)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int control;
+	int ret;
+
+	switch (reg) {
+	case LTC2945_POWER_H:
+	case LTC2945_MAX_POWER_H:
+	case LTC2945_MIN_POWER_H:
+	case LTC2945_MAX_POWER_THRES_H:
+	case LTC2945_MIN_POWER_THRES_H:
+		/*
+		 * Convert to register value by assuming current is measured
+		 * with an 1mOhm sense resistor, similar to current
+		 * measurements.
+		 * Control register bit 0 selects if voltage at SENSE+/VDD
+		 * or voltage at ADIN is used to measure power, which in turn
+		 * determines register calculations.
+		 */
+		ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+		if (ret < 0)
+			return ret;
+		if (control & CONTROL_MULT_SELECT) {
+			/* 25 mV * 25 uV = 0.625 uV resolution. */
+			val = DIV_ROUND_CLOSEST(val, 625);
+		} else {
+			/*
+			 * 0.5 mV * 25 uV = 0.0125 uV resolution.
+			 * Divide first to avoid overflow;
+			 * accept loss of accuracy.
+			 */
+			val = DIV_ROUND_CLOSEST(val, 25) * 2;
+		}
+		break;
+	case LTC2945_VIN_H:
+	case LTC2945_MAX_VIN_H:
+	case LTC2945_MIN_VIN_H:
+	case LTC2945_MAX_VIN_THRES_H:
+	case LTC2945_MIN_VIN_THRES_H:
+		/* 25 mV resolution. */
+		val /= 25;
+		break;
+	case LTC2945_ADIN_H:
+	case LTC2945_MAX_ADIN_H:
+	case LTC2945_MIN_ADIN_THRES_H:
+	case LTC2945_MAX_ADIN_THRES_H:
+	case LTC2945_MIN_ADIN_H:
+		/* 0.5mV resolution. */
+		val *= 2;
+		break;
+	case LTC2945_SENSE_H:
+	case LTC2945_MAX_SENSE_H:
+	case LTC2945_MIN_SENSE_H:
+	case LTC2945_MAX_SENSE_THRES_H:
+	case LTC2945_MIN_SENSE_THRES_H:
+		/*
+		 * 25 uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val = DIV_ROUND_CLOSEST(val, 25);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return val;
+}
+
+static ssize_t ltc2945_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	long long value;
+
+	value = ltc2945_reg_to_val(dev, attr->index);
+	if (value < 0)
+		return value;
+	return snprintf(buf, PAGE_SIZE, "%lld\n", value);
+}
+
+static ssize_t ltc2945_set_value(struct device *dev,
+				     struct device_attribute *da,
+				     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	u8 reg = attr->index;
+	unsigned long val;
+	u8 regbuf[3];
+	int num_regs;
+	int regval;
+	int ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	/* convert to register value, then clamp and write result */
+	regval = ltc2945_val_to_reg(dev, reg, val);
+	if (is_power_reg(reg)) {
+		regval = clamp_val(regval, 0, 0xffffff);
+		regbuf[0] = regval >> 16;
+		regbuf[1] = (regval >> 8) & 0xff;
+		regbuf[2] = regval;
+		num_regs = 3;
+	} else {
+		regval = clamp_val(regval, 0, 0xfff) << 4;
+		regbuf[0] = regval >> 8;
+		regbuf[1] = regval & 0xff;
+		num_regs = 2;
+	}
+	ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
+	return ret < 0 ? ret : count;
+}
+
+static ssize_t ltc2945_reset_history(struct device *dev,
+				     struct device_attribute *da,
+				     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	u8 reg = attr->index;
+	int num_regs = is_power_reg(reg) ? 3 : 2;
+	u8 buf_min[3] = { 0xff, 0xff, 0xff };
+	u8 buf_max[3] = { 0, 0, 0 };
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+	if (val != 1)
+		return -EINVAL;
+
+	ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
+				 CONTROL_TEST_MODE);
+
+	/* Reset minimum */
+	ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
+	if (ret)
+		return ret;
+
+	switch (reg) {
+	case LTC2945_MIN_POWER_H:
+		reg = LTC2945_MAX_POWER_H;
+		break;
+	case LTC2945_MIN_SENSE_H:
+		reg = LTC2945_MAX_SENSE_H;
+		break;
+	case LTC2945_MIN_VIN_H:
+		reg = LTC2945_MAX_VIN_H;
+		break;
+	case LTC2945_MIN_ADIN_H:
+		reg = LTC2945_MAX_ADIN_H;
+		break;
+	default:
+		WARN_ONCE(1, "Bad register: 0x%x\n", reg);
+		return -EINVAL;
+	}
+	/* Reset maximum */
+	ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
+
+	/* Try resetting test mode even if there was an error */
+	regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
+
+	return ret ? : count;
+}
+
+static ssize_t ltc2945_show_bool(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int fault;
+	int ret;
+
+	ret = regmap_read(regmap, LTC2945_FAULT, &fault);
+	if (ret < 0)
+		return ret;
+
+	fault &= attr->index;
+	if (fault)		/* Clear reported faults in chip register */
+		regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Input voltages */
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MIN_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MAX_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MIN_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MAX_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+			  ltc2945_reset_history, LTC2945_MIN_VIN_H);
+
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MIN_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MAX_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL,
+			  ltc2945_reset_history, LTC2945_MIN_ADIN_H);
+
+/* Voltage alarms */
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_VIN_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_VIN_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_ADIN_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_ADIN_OV);
+
+/* Currents (via sense resistor) */
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MIN_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_MAX_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
+			  ltc2945_reset_history, LTC2945_MIN_SENSE_H);
+
+/* Current alarms */
+
+static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_SENSE_UV);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_SENSE_OV);
+
+/* Power */
+
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL,
+			  LTC2945_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MIN_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+			  ltc2945_set_value, LTC2945_MAX_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value,
+			  NULL, LTC2945_MIN_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value,
+			  NULL, LTC2945_MAX_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+			  ltc2945_reset_history, LTC2945_MIN_POWER_H);
+
+/* Power alarms */
+
+static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_POWER_UV);
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+			  FAULT_POWER_OV);
+
+static struct attribute *ltc2945_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_lowest.dev_attr.attr,
+	&sensor_dev_attr_in1_highest.dev_attr.attr,
+	&sensor_dev_attr_in1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_lowest.dev_attr.attr,
+	&sensor_dev_attr_in2_highest.dev_attr.attr,
+	&sensor_dev_attr_in2_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_min.dev_attr.attr,
+	&sensor_dev_attr_curr1_max.dev_attr.attr,
+	&sensor_dev_attr_curr1_lowest.dev_attr.attr,
+	&sensor_dev_attr_curr1_highest.dev_attr.attr,
+	&sensor_dev_attr_curr1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_min.dev_attr.attr,
+	&sensor_dev_attr_power1_max.dev_attr.attr,
+	&sensor_dev_attr_power1_input_lowest.dev_attr.attr,
+	&sensor_dev_attr_power1_input_highest.dev_attr.attr,
+	&sensor_dev_attr_power1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_power1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc2945);
+
+static const struct regmap_config ltc2945_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = LTC2945_MIN_ADIN_THRES_L,
+};
+
+static int ltc2945_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	/* Clear faults */
+	regmap_write(regmap, LTC2945_FAULT, 0x00);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   regmap,
+							   ltc2945_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc2945_id[] = {
+	{"ltc2945", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc2945_id);
+
+static struct i2c_driver ltc2945_driver = {
+	.driver = {
+		   .name = "ltc2945",
+		   },
+	.probe = ltc2945_probe,
+	.id_table = ltc2945_id,
+};
+
+module_i2c_driver(ltc2945_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC2945 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
new file mode 100644
index 0000000..c86a184
--- /dev/null
+++ b/drivers/hwmon/ltc4151.c
@@ -0,0 +1,215 @@
+/*
+ * Driver for Linear Technology LTC4151 High Voltage I2C Current
+ * and Voltage Monitor
+ *
+ * Copyright (C) 2011 AppearTV AS
+ *
+ * Derived from:
+ *
+ *  Driver for Linear Technology LTC4261 I2C Negative Voltage Hot
+ *  Swap Controller
+ *  Copyright (C) 2010 Ericsson AB.
+ *
+ * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.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/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/jiffies.h>
+
+/* chip registers */
+#define LTC4151_SENSE_H	0x00
+#define LTC4151_SENSE_L	0x01
+#define LTC4151_VIN_H	0x02
+#define LTC4151_VIN_L	0x03
+#define LTC4151_ADIN_H	0x04
+#define LTC4151_ADIN_L	0x05
+
+struct ltc4151_data {
+	struct i2c_client *client;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+
+	/* Registers */
+	u8 regs[6];
+};
+
+static struct ltc4151_data *ltc4151_update_device(struct device *dev)
+{
+	struct ltc4151_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct ltc4151_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	/*
+	 * The chip's A/D updates 6 times per second
+	 * (Conversion Rate 6 - 9 Hz)
+	 */
+	if (time_after(jiffies, data->last_updated + HZ / 6) || !data->valid) {
+		int i;
+
+		dev_dbg(&client->dev, "Starting ltc4151 update\n");
+
+		/* Read all registers */
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			int val;
+
+			val = i2c_smbus_read_byte_data(client, i);
+			if (unlikely(val < 0)) {
+				dev_dbg(dev,
+					"Failed to read ADC value: error %d\n",
+					val);
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->regs[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* Return the voltage from the given register in mV */
+static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)
+{
+	u32 val;
+
+	val = (data->regs[reg] << 4) + (data->regs[reg + 1] >> 4);
+
+	switch (reg) {
+	case LTC4151_ADIN_H:
+		/* 500uV resolution. Convert to mV. */
+		val = val * 500 / 1000;
+		break;
+	case LTC4151_SENSE_H:
+		/*
+		 * 20uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA.
+		 */
+		val = val * 20;
+		break;
+	case LTC4151_VIN_H:
+		/* 25 mV per increment */
+		val = val * 25;
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static ssize_t ltc4151_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4151_data *data = ltc4151_update_device(dev);
+	int value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = ltc4151_get_value(data, attr->index);
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/*
+ * Input voltages.
+ */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4151_show_value, NULL,
+			  LTC4151_VIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4151_show_value, NULL,
+			  LTC4151_ADIN_H);
+
+/* Currents (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL,
+			  LTC4151_SENSE_H);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4151_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc4151);
+
+static int ltc4151_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct ltc4151_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   ltc4151_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4151_id[] = {
+	{ "ltc4151", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4151_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4151_driver = {
+	.driver = {
+		.name	= "ltc4151",
+	},
+	.probe		= ltc4151_probe,
+	.id_table	= ltc4151_id,
+};
+
+module_i2c_driver(ltc4151_driver);
+
+MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
+MODULE_DESCRIPTION("LTC4151 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
new file mode 100644
index 0000000..c8a9bd9
--- /dev/null
+++ b/drivers/hwmon/ltc4215.c
@@ -0,0 +1,280 @@
+/*
+ * Driver for Linear Technology LTC4215 I2C Hot Swap Controller
+ *
+ * Copyright (C) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697
+ */
+
+#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/jiffies.h>
+
+/* Here are names of the chip's registers (a.k.a. commands) */
+enum ltc4215_cmd {
+	LTC4215_CONTROL			= 0x00, /* rw */
+	LTC4215_ALERT			= 0x01, /* rw */
+	LTC4215_STATUS			= 0x02, /* ro */
+	LTC4215_FAULT			= 0x03, /* rw */
+	LTC4215_SENSE			= 0x04, /* rw */
+	LTC4215_SOURCE			= 0x05, /* rw */
+	LTC4215_ADIN			= 0x06, /* rw */
+};
+
+struct ltc4215_data {
+	struct i2c_client *client;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+
+	/* Registers */
+	u8 regs[7];
+};
+
+static struct ltc4215_data *ltc4215_update_device(struct device *dev)
+{
+	struct ltc4215_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	s32 val;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	/* The chip's A/D updates 10 times per second */
+	if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting ltc4215 update\n");
+
+		/* Read all registers */
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			val = i2c_smbus_read_byte_data(client, i);
+			if (unlikely(val < 0))
+				data->regs[i] = 0;
+			else
+				data->regs[i] = val;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* Return the voltage from the given register in millivolts */
+static int ltc4215_get_voltage(struct device *dev, u8 reg)
+{
+	struct ltc4215_data *data = ltc4215_update_device(dev);
+	const u8 regval = data->regs[reg];
+	u32 voltage = 0;
+
+	switch (reg) {
+	case LTC4215_SENSE:
+		/* 151 uV per increment */
+		voltage = regval * 151 / 1000;
+		break;
+	case LTC4215_SOURCE:
+		/* 60.5 mV per increment */
+		voltage = regval * 605 / 10;
+		break;
+	case LTC4215_ADIN:
+		/*
+		 * The ADIN input is divided by 12.5, and has 4.82 mV
+		 * per increment, so we have the additional multiply
+		 */
+		voltage = regval * 482 * 125 / 1000;
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		break;
+	}
+
+	return voltage;
+}
+
+/* Return the current from the sense resistor in mA */
+static unsigned int ltc4215_get_current(struct device *dev)
+{
+	struct ltc4215_data *data = ltc4215_update_device(dev);
+
+	/*
+	 * The strange looking conversions that follow are fixed-point
+	 * math, since we cannot do floating point in the kernel.
+	 *
+	 * Step 1: convert sense register to microVolts
+	 * Step 2: convert voltage to milliAmperes
+	 *
+	 * If you play around with the V=IR equation, you come up with
+	 * the following: X uV / Y mOhm == Z mA
+	 *
+	 * With the resistors that are fractions of a milliOhm, we multiply
+	 * the voltage and resistance by 10, to shift the decimal point.
+	 * Now we can use the normal division operator again.
+	 */
+
+	/* Calculate voltage in microVolts (151 uV per increment) */
+	const unsigned int voltage = data->regs[LTC4215_SENSE] * 151;
+
+	/* Calculate current in milliAmperes (4 milliOhm sense resistor) */
+	const unsigned int curr = voltage / 4;
+
+	return curr;
+}
+
+static ssize_t ltc4215_show_voltage(struct device *dev,
+				    struct device_attribute *da,
+				    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	const int voltage = ltc4215_get_voltage(dev, attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+}
+
+static ssize_t ltc4215_show_current(struct device *dev,
+				    struct device_attribute *da,
+				    char *buf)
+{
+	const unsigned int curr = ltc4215_get_current(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+}
+
+static ssize_t ltc4215_show_power(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	const unsigned int curr = ltc4215_get_current(dev);
+	const int output_voltage = ltc4215_get_voltage(dev, LTC4215_ADIN);
+
+	/* current in mA * voltage in mV == power in uW */
+	const unsigned int power = abs(output_voltage * curr);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", power);
+}
+
+static ssize_t ltc4215_show_alarm(struct device *dev,
+					  struct device_attribute *da,
+					  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4215_data *data = ltc4215_update_device(dev);
+	const u8 reg = data->regs[LTC4215_STATUS];
+	const u32 mask = attr->index;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
+}
+
+/*
+ * These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4215_show_current, NULL, 0);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+			  1 << 2);
+
+/* Power (virtual) */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4215_show_power, NULL, 0);
+
+/* Input Voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4215_show_voltage, NULL,
+			  LTC4215_ADIN);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+			  1 << 0);
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+			  1 << 1);
+
+/* Output Voltage */
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4215_show_voltage, NULL,
+			  LTC4215_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+			  1 << 3);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4215_attrs[] = {
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc4215);
+
+static int ltc4215_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct ltc4215_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the LTC4215 chip */
+	i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   ltc4215_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4215_id[] = {
+	{ "ltc4215", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4215_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4215_driver = {
+	.driver = {
+		.name	= "ltc4215",
+	},
+	.probe		= ltc4215_probe,
+	.id_table	= ltc4215_id,
+};
+
+module_i2c_driver(ltc4215_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("LTC4215 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c
new file mode 100644
index 0000000..88f7472
--- /dev/null
+++ b/drivers/hwmon/ltc4222.c
@@ -0,0 +1,237 @@
+/*
+ * Driver for Linear Technology LTC4222 Dual Hot Swap controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+
+#define LTC4222_CONTROL1	0xd0
+#define LTC4222_ALERT1		0xd1
+#define LTC4222_STATUS1		0xd2
+#define LTC4222_FAULT1		0xd3
+#define LTC4222_CONTROL2	0xd4
+#define LTC4222_ALERT2		0xd5
+#define LTC4222_STATUS2		0xd6
+#define LTC4222_FAULT2		0xd7
+#define LTC4222_SOURCE1		0xd8
+#define LTC4222_SOURCE2		0xda
+#define LTC4222_ADIN1		0xdc
+#define LTC4222_ADIN2		0xde
+#define LTC4222_SENSE1		0xe0
+#define LTC4222_SENSE2		0xe2
+#define LTC4222_ADC_CONTROL	0xe4
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV	BIT(0)
+#define FAULT_UV	BIT(1)
+#define FAULT_OC	BIT(2)
+#define FAULT_POWER_BAD	BIT(3)
+#define FAULT_FET_BAD	BIT(5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4222_get_value(struct device *dev, u8 reg)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int val;
+	u8 buf[2];
+	int ret;
+
+	ret = regmap_bulk_read(regmap, reg, buf, 2);
+	if (ret < 0)
+		return ret;
+
+	val = ((buf[0] << 8) + buf[1]) >> 6;
+
+	switch (reg) {
+	case LTC4222_ADIN1:
+	case LTC4222_ADIN2:
+		/* 1.25 mV resolution. Convert to mV. */
+		val = DIV_ROUND_CLOSEST(val * 5, 4);
+		break;
+	case LTC4222_SOURCE1:
+	case LTC4222_SOURCE2:
+		/* 31.25 mV resolution. Convert to mV. */
+		val = DIV_ROUND_CLOSEST(val * 125, 4);
+		break;
+	case LTC4222_SENSE1:
+	case LTC4222_SENSE2:
+		/*
+		 * 62.5 uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val = DIV_ROUND_CLOSEST(val * 125, 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return val;
+}
+
+static ssize_t ltc4222_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int value;
+
+	value = ltc4222_get_value(dev, attr->index);
+	if (value < 0)
+		return value;
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4222_show_bool(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int fault;
+	int ret;
+
+	ret = regmap_read(regmap, attr->nr, &fault);
+	if (ret < 0)
+		return ret;
+	fault &= attr->index;
+	if (fault)		/* Clear reported faults in chip register */
+		regmap_update_bits(regmap, attr->nr, attr->index, 0);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_SOURCE1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_ADIN1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_SOURCE2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_ADIN2);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and power bad and fet
+ * faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT1, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT1, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT2, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT2, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_SENSE1);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
+			  LTC4222_SENSE2);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT1, FAULT_OC);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+			    LTC4222_FAULT2, FAULT_OC);
+
+static struct attribute *ltc4222_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr2_input.dev_attr.attr,
+	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc4222);
+
+static const struct regmap_config ltc4222_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = LTC4222_ADC_CONTROL,
+};
+
+static int ltc4222_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &ltc4222_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	/* Clear faults */
+	regmap_write(regmap, LTC4222_FAULT1, 0x00);
+	regmap_write(regmap, LTC4222_FAULT2, 0x00);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   regmap,
+							   ltc4222_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4222_id[] = {
+	{"ltc4222", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4222_id);
+
+static struct i2c_driver ltc4222_driver = {
+	.driver = {
+		   .name = "ltc4222",
+		   },
+	.probe = ltc4222_probe,
+	.id_table = ltc4222_id,
+};
+
+module_i2c_driver(ltc4222_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4222 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
new file mode 100644
index 0000000..681b5b7
--- /dev/null
+++ b/drivers/hwmon/ltc4245.c
@@ -0,0 +1,533 @@
+/*
+ * Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ *
+ * Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * 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 driver is based on the ds1621 and ina209 drivers.
+ *
+ * Datasheet:
+ * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1140,P19392,D13517
+ */
+
+#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/jiffies.h>
+#include <linux/i2c/ltc4245.h>
+
+/* Here are names of the chip's registers (a.k.a. commands) */
+enum ltc4245_cmd {
+	LTC4245_STATUS			= 0x00, /* readonly */
+	LTC4245_ALERT			= 0x01,
+	LTC4245_CONTROL			= 0x02,
+	LTC4245_ON			= 0x03,
+	LTC4245_FAULT1			= 0x04,
+	LTC4245_FAULT2			= 0x05,
+	LTC4245_GPIO			= 0x06,
+	LTC4245_ADCADR			= 0x07,
+
+	LTC4245_12VIN			= 0x10,
+	LTC4245_12VSENSE		= 0x11,
+	LTC4245_12VOUT			= 0x12,
+	LTC4245_5VIN			= 0x13,
+	LTC4245_5VSENSE			= 0x14,
+	LTC4245_5VOUT			= 0x15,
+	LTC4245_3VIN			= 0x16,
+	LTC4245_3VSENSE			= 0x17,
+	LTC4245_3VOUT			= 0x18,
+	LTC4245_VEEIN			= 0x19,
+	LTC4245_VEESENSE		= 0x1a,
+	LTC4245_VEEOUT			= 0x1b,
+	LTC4245_GPIOADC			= 0x1c,
+};
+
+struct ltc4245_data {
+	struct i2c_client *client;
+
+	const struct attribute_group *groups[3];
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+
+	/* Control registers */
+	u8 cregs[0x08];
+
+	/* Voltage registers */
+	u8 vregs[0x0d];
+
+	/* GPIO ADC registers */
+	bool use_extra_gpios;
+	int gpios[3];
+};
+
+/*
+ * Update the readings from the GPIO pins. If the driver has been configured to
+ * sample all GPIO's as analog voltages, a round-robin sampling method is used.
+ * Otherwise, only the configured GPIO pin is sampled.
+ *
+ * LOCKING: must hold data->update_lock
+ */
+static void ltc4245_update_gpios(struct device *dev)
+{
+	struct ltc4245_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 gpio_curr, gpio_next, gpio_reg;
+	int i;
+
+	/* no extra gpio support, we're basically done */
+	if (!data->use_extra_gpios) {
+		data->gpios[0] = data->vregs[LTC4245_GPIOADC - 0x10];
+		return;
+	}
+
+	/*
+	 * If the last reading was too long ago, then we mark all old GPIO
+	 * readings as stale by setting them to -EAGAIN
+	 */
+	if (time_after(jiffies, data->last_updated + 5 * HZ)) {
+		for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
+			data->gpios[i] = -EAGAIN;
+	}
+
+	/*
+	 * Get the current GPIO pin
+	 *
+	 * The datasheet calls these GPIO[1-3], but we'll calculate the zero
+	 * based array index instead, and call them GPIO[0-2]. This is much
+	 * easier to think about.
+	 */
+	gpio_curr = (data->cregs[LTC4245_GPIO] & 0xc0) >> 6;
+	if (gpio_curr > 0)
+		gpio_curr -= 1;
+
+	/* Read the GPIO voltage from the GPIOADC register */
+	data->gpios[gpio_curr] = data->vregs[LTC4245_GPIOADC - 0x10];
+
+	/* Find the next GPIO pin to read */
+	gpio_next = (gpio_curr + 1) % ARRAY_SIZE(data->gpios);
+
+	/*
+	 * Calculate the correct setting for the GPIO register so it will
+	 * sample the next GPIO pin
+	 */
+	gpio_reg = (data->cregs[LTC4245_GPIO] & 0x3f) | ((gpio_next + 1) << 6);
+
+	/* Update the GPIO register */
+	i2c_smbus_write_byte_data(client, LTC4245_GPIO, gpio_reg);
+
+	/* Update saved data */
+	data->cregs[LTC4245_GPIO] = gpio_reg;
+}
+
+static struct ltc4245_data *ltc4245_update_device(struct device *dev)
+{
+	struct ltc4245_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	s32 val;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+
+		/* Read control registers -- 0x00 to 0x07 */
+		for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
+			val = i2c_smbus_read_byte_data(client, i);
+			if (unlikely(val < 0))
+				data->cregs[i] = 0;
+			else
+				data->cregs[i] = val;
+		}
+
+		/* Read voltage registers -- 0x10 to 0x1c */
+		for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
+			val = i2c_smbus_read_byte_data(client, i+0x10);
+			if (unlikely(val < 0))
+				data->vregs[i] = 0;
+			else
+				data->vregs[i] = val;
+		}
+
+		/* Update GPIO readings */
+		ltc4245_update_gpios(dev);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* Return the voltage from the given register in millivolts */
+static int ltc4245_get_voltage(struct device *dev, u8 reg)
+{
+	struct ltc4245_data *data = ltc4245_update_device(dev);
+	const u8 regval = data->vregs[reg - 0x10];
+	u32 voltage = 0;
+
+	switch (reg) {
+	case LTC4245_12VIN:
+	case LTC4245_12VOUT:
+		voltage = regval * 55;
+		break;
+	case LTC4245_5VIN:
+	case LTC4245_5VOUT:
+		voltage = regval * 22;
+		break;
+	case LTC4245_3VIN:
+	case LTC4245_3VOUT:
+		voltage = regval * 15;
+		break;
+	case LTC4245_VEEIN:
+	case LTC4245_VEEOUT:
+		voltage = regval * -55;
+		break;
+	case LTC4245_GPIOADC:
+		voltage = regval * 10;
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		break;
+	}
+
+	return voltage;
+}
+
+/* Return the current in the given sense register in milliAmperes */
+static unsigned int ltc4245_get_current(struct device *dev, u8 reg)
+{
+	struct ltc4245_data *data = ltc4245_update_device(dev);
+	const u8 regval = data->vregs[reg - 0x10];
+	unsigned int voltage;
+	unsigned int curr;
+
+	/*
+	 * The strange looking conversions that follow are fixed-point
+	 * math, since we cannot do floating point in the kernel.
+	 *
+	 * Step 1: convert sense register to microVolts
+	 * Step 2: convert voltage to milliAmperes
+	 *
+	 * If you play around with the V=IR equation, you come up with
+	 * the following: X uV / Y mOhm == Z mA
+	 *
+	 * With the resistors that are fractions of a milliOhm, we multiply
+	 * the voltage and resistance by 10, to shift the decimal point.
+	 * Now we can use the normal division operator again.
+	 */
+
+	switch (reg) {
+	case LTC4245_12VSENSE:
+		voltage = regval * 250; /* voltage in uV */
+		curr = voltage / 50; /* sense resistor 50 mOhm */
+		break;
+	case LTC4245_5VSENSE:
+		voltage = regval * 125; /* voltage in uV */
+		curr = (voltage * 10) / 35; /* sense resistor 3.5 mOhm */
+		break;
+	case LTC4245_3VSENSE:
+		voltage = regval * 125; /* voltage in uV */
+		curr = (voltage * 10) / 25; /* sense resistor 2.5 mOhm */
+		break;
+	case LTC4245_VEESENSE:
+		voltage = regval * 250; /* voltage in uV */
+		curr = voltage / 100; /* sense resistor 100 mOhm */
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		curr = 0;
+		break;
+	}
+
+	return curr;
+}
+
+static ssize_t ltc4245_show_voltage(struct device *dev,
+				    struct device_attribute *da,
+				    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	const int voltage = ltc4245_get_voltage(dev, attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+}
+
+static ssize_t ltc4245_show_current(struct device *dev,
+				    struct device_attribute *da,
+				    char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	const unsigned int curr = ltc4245_get_current(dev, attr->index);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+}
+
+static ssize_t ltc4245_show_power(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	const unsigned int curr = ltc4245_get_current(dev, attr->index);
+	const int output_voltage = ltc4245_get_voltage(dev, attr->index+1);
+
+	/* current in mA * voltage in mV == power in uW */
+	const unsigned int power = abs(output_voltage * curr);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", power);
+}
+
+static ssize_t ltc4245_show_alarm(struct device *dev,
+					  struct device_attribute *da,
+					  char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+	struct ltc4245_data *data = ltc4245_update_device(dev);
+	const u8 reg = data->cregs[attr->index];
+	const u32 mask = attr->nr;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+}
+
+static ssize_t ltc4245_show_gpio(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4245_data *data = ltc4245_update_device(dev);
+	int val = data->gpios[attr->index];
+
+	/* handle stale GPIO's */
+	if (val < 0)
+		return val;
+
+	/* Convert to millivolts and print */
+	return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
+}
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Input voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_12VIN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_5VIN);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_3VIN);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_VEEIN);
+
+/* Input undervoltage alarms */
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 0, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 1, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 2, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 3, LTC4245_FAULT1);
+
+/* Currents (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
+			  LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
+			  LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
+			  LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
+			  LTC4245_VEESENSE);
+
+/* Overcurrent alarms */
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 4, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 5, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 6, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 7, LTC4245_FAULT1);
+
+/* Output voltages */
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_12VOUT);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_5VOUT);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_3VOUT);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
+			  LTC4245_VEEOUT);
+
+/* Power Bad alarms */
+static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 0, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 1, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 2, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+			    1 << 3, LTC4245_FAULT2);
+
+/* GPIO voltages */
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
+
+/* Power Consumption (virtual) */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
+			  LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
+			  LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
+			  LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
+			  LTC4245_VEESENSE);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4245_std_attributes[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr2_input.dev_attr.attr,
+	&sensor_dev_attr_curr3_input.dev_attr.attr,
+	&sensor_dev_attr_curr4_input.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr4_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+
+	&sensor_dev_attr_in5_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in8_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	&sensor_dev_attr_power2_input.dev_attr.attr,
+	&sensor_dev_attr_power3_input.dev_attr.attr,
+	&sensor_dev_attr_power4_input.dev_attr.attr,
+
+	NULL,
+};
+
+static struct attribute *ltc4245_gpio_attributes[] = {
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ltc4245_std_group = {
+	.attrs = ltc4245_std_attributes,
+};
+
+static const struct attribute_group ltc4245_gpio_group = {
+	.attrs = ltc4245_gpio_attributes,
+};
+
+static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
+{
+	/* standard sysfs attributes */
+	data->groups[0] = &ltc4245_std_group;
+
+	/* if we're using the extra gpio support, register it's attributes */
+	if (data->use_extra_gpios)
+		data->groups[1] = &ltc4245_gpio_group;
+}
+
+static bool ltc4245_use_extra_gpios(struct i2c_client *client)
+{
+	struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct device_node *np = client->dev.of_node;
+
+	/* prefer platform data */
+	if (pdata)
+		return pdata->use_extra_gpios;
+
+	/* fallback on OF */
+	if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
+		return true;
+
+	return false;
+}
+
+static int ltc4245_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct ltc4245_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+	data->use_extra_gpios = ltc4245_use_extra_gpios(client);
+
+	/* Initialize the LTC4245 chip */
+	i2c_smbus_write_byte_data(client, LTC4245_FAULT1, 0x00);
+	i2c_smbus_write_byte_data(client, LTC4245_FAULT2, 0x00);
+
+	/* Add sysfs hooks */
+	ltc4245_sysfs_add_groups(data);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4245_id[] = {
+	{ "ltc4245", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4245_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4245_driver = {
+	.driver = {
+		.name	= "ltc4245",
+	},
+	.probe		= ltc4245_probe,
+	.id_table	= ltc4245_id,
+};
+
+module_i2c_driver(ltc4245_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("LTC4245 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c
new file mode 100644
index 0000000..afb0957
--- /dev/null
+++ b/drivers/hwmon/ltc4260.c
@@ -0,0 +1,200 @@
+/*
+ * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC4260_CONTROL	0x00
+#define LTC4260_ALERT	0x01
+#define LTC4260_STATUS	0x02
+#define LTC4260_FAULT	0x03
+#define LTC4260_SENSE	0x04
+#define LTC4260_SOURCE	0x05
+#define LTC4260_ADIN	0x06
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV	(1 << 0)
+#define FAULT_UV	(1 << 1)
+#define FAULT_OC	(1 << 2)
+#define FAULT_POWER_BAD	(1 << 3)
+#define FAULT_FET_SHORT	(1 << 5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4260_get_value(struct device *dev, u8 reg)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, reg, &val);
+	if (ret < 0)
+		return ret;
+
+	switch (reg) {
+	case LTC4260_ADIN:
+		/* 10 mV resolution. Convert to mV. */
+		val = val * 10;
+		break;
+	case LTC4260_SOURCE:
+		/* 400 mV resolution. Convert to mV. */
+		val = val * 400;
+		break;
+	case LTC4260_SENSE:
+		/*
+		 * 300 uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val = val * 300;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return val;
+}
+
+static ssize_t ltc4260_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int value;
+
+	value = ltc4260_get_value(dev, attr->index);
+	if (value < 0)
+		return value;
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4260_show_bool(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int fault;
+	int ret;
+
+	ret = regmap_read(regmap, LTC4260_FAULT, &fault);
+	if (ret < 0)
+		return ret;
+
+	fault &= attr->index;
+	if (fault)		/* Clear reported faults in chip register */
+		regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL,
+			  LTC4260_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL,
+			  LTC4260_ADIN);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and the POWER BAD and
+ * FET SHORT faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+			  FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+			  FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+			  FAULT_POWER_BAD | FAULT_FET_SHORT);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL,
+			  LTC4260_SENSE);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+			  FAULT_OC);
+
+static struct attribute *ltc4260_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc4260);
+
+static const struct regmap_config ltc4260_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = LTC4260_ADIN,
+};
+
+static int ltc4260_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	/* Clear faults */
+	regmap_write(regmap, LTC4260_FAULT, 0x00);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   regmap,
+							   ltc4260_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4260_id[] = {
+	{"ltc4260", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4260_id);
+
+static struct i2c_driver ltc4260_driver = {
+	.driver = {
+		   .name = "ltc4260",
+		   },
+	.probe = ltc4260_probe,
+	.id_table = ltc4260_id,
+};
+
+module_i2c_driver(ltc4260_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4260 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
new file mode 100644
index 0000000..0becd69
--- /dev/null
+++ b/drivers/hwmon/ltc4261.c
@@ -0,0 +1,266 @@
+/*
+ * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot Swap Controller
+ *
+ * Copyright (C) 2010 Ericsson AB.
+ *
+ * Derived from:
+ *
+ *  Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ *  Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Datasheet: http://cds.linear.com/docs/Datasheet/42612fb.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/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/jiffies.h>
+
+/* chip registers */
+#define LTC4261_STATUS	0x00	/* readonly */
+#define LTC4261_FAULT	0x01
+#define LTC4261_ALERT	0x02
+#define LTC4261_CONTROL	0x03
+#define LTC4261_SENSE_H	0x04
+#define LTC4261_SENSE_L	0x05
+#define LTC4261_ADIN2_H	0x06
+#define LTC4261_ADIN2_L	0x07
+#define LTC4261_ADIN_H	0x08
+#define LTC4261_ADIN_L	0x09
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV	(1<<0)
+#define FAULT_UV	(1<<1)
+#define FAULT_OC	(1<<2)
+
+struct ltc4261_data {
+	struct i2c_client *client;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+
+	/* Registers */
+	u8 regs[10];
+};
+
+static struct ltc4261_data *ltc4261_update_device(struct device *dev)
+{
+	struct ltc4261_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct ltc4261_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ / 4) || !data->valid) {
+		int i;
+
+		/* Read registers -- 0x00 to 0x09 */
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			int val;
+
+			val = i2c_smbus_read_byte_data(client, i);
+			if (unlikely(val < 0)) {
+				dev_dbg(dev,
+					"Failed to read ADC value: error %d\n",
+					val);
+				ret = ERR_PTR(val);
+				data->valid = 0;
+				goto abort;
+			}
+			data->regs[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4261_get_value(struct ltc4261_data *data, u8 reg)
+{
+	u32 val;
+
+	val = (data->regs[reg] << 2) + (data->regs[reg + 1] >> 6);
+
+	switch (reg) {
+	case LTC4261_ADIN_H:
+	case LTC4261_ADIN2_H:
+		/* 2.5mV resolution. Convert to mV. */
+		val = val * 25 / 10;
+		break;
+	case LTC4261_SENSE_H:
+		/*
+		 * 62.5uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val = val * 625 / 10;
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static ssize_t ltc4261_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4261_data *data = ltc4261_update_device(dev);
+	int value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = ltc4261_get_value(data, attr->index);
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4261_show_bool(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4261_data *data = ltc4261_update_device(dev);
+	u8 fault;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	fault = data->regs[LTC4261_FAULT] & attr->index;
+	if (fault)		/* Clear reported faults in chip register */
+		i2c_smbus_write_byte_data(data->client, LTC4261_FAULT, ~fault);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
+}
+
+/*
+ * Input voltages.
+ */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4261_show_value, NULL,
+			  LTC4261_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4261_show_value, NULL,
+			  LTC4261_ADIN2_H);
+
+/*
+ * Voltage alarms. The chip has only one set of voltage alarm status bits,
+ * triggered by input voltage alarms. In many designs, those alarms are
+ * associated with the ADIN2 sensor, due to the proximity of the ADIN2 pin
+ * to the OV pin. ADIN2 is, however, not available on all chip variants.
+ * To ensure that the alarm condition is reported to the user, report it
+ * with both voltage sensors.
+ */
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+			  FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+			  FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+			  FAULT_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+			  FAULT_OV);
+
+/* Currents (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL,
+			  LTC4261_SENSE_H);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+			  FAULT_OC);
+
+static struct attribute *ltc4261_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+	NULL,
+};
+ATTRIBUTE_GROUPS(ltc4261);
+
+static int ltc4261_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct ltc4261_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
+		dev_err(dev, "Failed to read status register\n");
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Clear faults */
+	i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   ltc4261_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4261_id[] = {
+	{"ltc4261", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4261_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4261_driver = {
+	.driver = {
+		   .name = "ltc4261",
+		   },
+	.probe = ltc4261_probe,
+	.id_table = ltc4261_id,
+};
+
+module_i2c_driver(ltc4261_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4261 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
new file mode 100644
index 0000000..303d0c9
--- /dev/null
+++ b/drivers/hwmon/max1111.c
@@ -0,0 +1,296 @@
+/*
+ * max1111.c - +2.7V, Low-Power, Multichannel, Serial 8-bit ADCs
+ *
+ * Based on arch/arm/mach-pxa/corgi_ssp.c
+ *
+ * Copyright (C) 2004-2005 Richard Purdie
+ *
+ * Copyright (C) 2008 Marvell International Ltd.
+ *	Eric Miao <eric.miao@marvell.com>
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+
+enum chips { max1110, max1111, max1112, max1113 };
+
+#define MAX1111_TX_BUF_SIZE	1
+#define MAX1111_RX_BUF_SIZE	2
+
+/* MAX1111 Commands */
+#define MAX1111_CTRL_PD0      (1u << 0)
+#define MAX1111_CTRL_PD1      (1u << 1)
+#define MAX1111_CTRL_SGL      (1u << 2)
+#define MAX1111_CTRL_UNI      (1u << 3)
+#define MAX1110_CTRL_SEL_SH   (4)
+#define MAX1111_CTRL_SEL_SH   (5)	/* NOTE: bit 4 is ignored */
+#define MAX1111_CTRL_STR      (1u << 7)
+
+struct max1111_data {
+	struct spi_device	*spi;
+	struct device		*hwmon_dev;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+	uint8_t tx_buf[MAX1111_TX_BUF_SIZE];
+	uint8_t rx_buf[MAX1111_RX_BUF_SIZE];
+	struct mutex		drvdata_lock;
+	/* protect msg, xfer and buffers from multiple access */
+	int			sel_sh;
+	int			lsb;
+};
+
+static int max1111_read(struct device *dev, int channel)
+{
+	struct max1111_data *data = dev_get_drvdata(dev);
+	uint8_t v1, v2;
+	int err;
+
+	/* writing to drvdata struct is not thread safe, wait on mutex */
+	mutex_lock(&data->drvdata_lock);
+
+	data->tx_buf[0] = (channel << data->sel_sh) |
+		MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 |
+		MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR;
+
+	err = spi_sync(data->spi, &data->msg);
+	if (err < 0) {
+		dev_err(dev, "spi_sync failed with %d\n", err);
+		mutex_unlock(&data->drvdata_lock);
+		return err;
+	}
+
+	v1 = data->rx_buf[0];
+	v2 = data->rx_buf[1];
+
+	mutex_unlock(&data->drvdata_lock);
+
+	if ((v1 & 0xc0) || (v2 & 0x3f))
+		return -EINVAL;
+
+	return (v1 << 2) | (v2 >> 6);
+}
+
+#ifdef CONFIG_SHARPSL_PM
+static struct max1111_data *the_max1111;
+
+int max1111_read_channel(int channel)
+{
+	if (!the_max1111 || !the_max1111->spi)
+		return -ENODEV;
+
+	return max1111_read(&the_max1111->spi->dev, channel);
+}
+EXPORT_SYMBOL(max1111_read_channel);
+#endif
+
+/*
+ * NOTE: SPI devices do not have a default 'name' attribute, which is
+ * likely to be used by hwmon applications to distinguish between
+ * different devices, explicitly add a name attribute here.
+ */
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
+static ssize_t show_adc(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct max1111_data *data = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(attr)->index;
+	int ret;
+
+	ret = max1111_read(dev, channel);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Assume the reference voltage to be 2.048V or 4.096V, with an 8-bit
+	 * sample. The LSB weight is 8mV or 16mV depending on the chip type.
+	 */
+	return sprintf(buf, "%d\n", ret * data->lsb);
+}
+
+#define MAX1111_ADC_ATTR(_id)		\
+	SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id)
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static MAX1111_ADC_ATTR(0);
+static MAX1111_ADC_ATTR(1);
+static MAX1111_ADC_ATTR(2);
+static MAX1111_ADC_ATTR(3);
+static MAX1111_ADC_ATTR(4);
+static MAX1111_ADC_ATTR(5);
+static MAX1111_ADC_ATTR(6);
+static MAX1111_ADC_ATTR(7);
+
+static struct attribute *max1111_attributes[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group max1111_attr_group = {
+	.attrs	= max1111_attributes,
+};
+
+static struct attribute *max1110_attributes[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group max1110_attr_group = {
+	.attrs	= max1110_attributes,
+};
+
+static int setup_transfer(struct max1111_data *data)
+{
+	struct spi_message *m;
+	struct spi_transfer *x;
+
+	m = &data->msg;
+	x = &data->xfer[0];
+
+	spi_message_init(m);
+
+	x->tx_buf = &data->tx_buf[0];
+	x->len = MAX1111_TX_BUF_SIZE;
+	spi_message_add_tail(x, m);
+
+	x++;
+	x->rx_buf = &data->rx_buf[0];
+	x->len = MAX1111_RX_BUF_SIZE;
+	spi_message_add_tail(x, m);
+
+	return 0;
+}
+
+static int max1111_probe(struct spi_device *spi)
+{
+	enum chips chip = spi_get_device_id(spi)->driver_data;
+	struct max1111_data *data;
+	int err;
+
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	err = spi_setup(spi);
+	if (err < 0)
+		return err;
+
+	data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	switch (chip) {
+	case max1110:
+		data->lsb = 8;
+		data->sel_sh = MAX1110_CTRL_SEL_SH;
+		break;
+	case max1111:
+		data->lsb = 8;
+		data->sel_sh = MAX1111_CTRL_SEL_SH;
+		break;
+	case max1112:
+		data->lsb = 16;
+		data->sel_sh = MAX1110_CTRL_SEL_SH;
+		break;
+	case max1113:
+		data->lsb = 16;
+		data->sel_sh = MAX1111_CTRL_SEL_SH;
+		break;
+	}
+	err = setup_transfer(data);
+	if (err)
+		return err;
+
+	mutex_init(&data->drvdata_lock);
+
+	data->spi = spi;
+	spi_set_drvdata(spi, data);
+
+	err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group);
+	if (err) {
+		dev_err(&spi->dev, "failed to create attribute group\n");
+		return err;
+	}
+	if (chip == max1110 || chip == max1112) {
+		err = sysfs_create_group(&spi->dev.kobj, &max1110_attr_group);
+		if (err) {
+			dev_err(&spi->dev,
+				"failed to create extended attribute group\n");
+			goto err_remove;
+		}
+	}
+
+	data->hwmon_dev = hwmon_device_register(&spi->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(&spi->dev, "failed to create hwmon device\n");
+		err = PTR_ERR(data->hwmon_dev);
+		goto err_remove;
+	}
+
+#ifdef CONFIG_SHARPSL_PM
+	the_max1111 = data;
+#endif
+	return 0;
+
+err_remove:
+	sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
+	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
+	return err;
+}
+
+static int max1111_remove(struct spi_device *spi)
+{
+	struct max1111_data *data = spi_get_drvdata(spi);
+
+#ifdef CONFIG_SHARPSL_PM
+	the_max1111 = NULL;
+#endif
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
+	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
+	mutex_destroy(&data->drvdata_lock);
+	return 0;
+}
+
+static const struct spi_device_id max1111_ids[] = {
+	{ "max1110", max1110 },
+	{ "max1111", max1111 },
+	{ "max1112", max1112 },
+	{ "max1113", max1113 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, max1111_ids);
+
+static struct spi_driver max1111_driver = {
+	.driver		= {
+		.name	= "max1111",
+	},
+	.id_table	= max1111_ids,
+	.probe		= max1111_probe,
+	.remove		= max1111_remove,
+};
+
+module_spi_driver(max1111_driver);
+
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("MAX1110/MAX1111/MAX1112/MAX1113 ADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
new file mode 100644
index 0000000..162401a
--- /dev/null
+++ b/drivers/hwmon/max16065.c
@@ -0,0 +1,673 @@
+/*
+ * 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/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 i2c_client *client;
+	const struct attribute_group *groups[4];
+	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 clamp_val(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_swapped(client, reg);
+	if (unlikely(rv < 0))
+		return rv;
+	return rv >> 6;
+}
+
+static struct max16065_data *max16065_update_device(struct device *dev)
+{
+	struct max16065_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->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(data->client,
+					  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 max16065_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+	int limit;
+
+	err = kstrtoul(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(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 max16065_data *data = dev_get_drvdata(dev);
+
+	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 umode_t max16065_basic_is_visible(struct kobject *kobj,
+					 struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct max16065_data *data = dev_get_drvdata(dev);
+	int index = n / 4;
+
+	if (index >= data->num_adc || !data->range[index])
+		return 0;
+	return a->mode;
+}
+
+static umode_t max16065_secondary_is_visible(struct kobject *kobj,
+					     struct attribute *a, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct max16065_data *data = dev_get_drvdata(dev);
+
+	if (index >= data->num_adc)
+		return 0;
+	return a->mode;
+}
+
+static const struct attribute_group max16065_basic_group = {
+	.attrs = max16065_basic_attributes,
+	.is_visible = max16065_basic_is_visible,
+};
+
+static const struct attribute_group max16065_current_group = {
+	.attrs = max16065_current_attributes,
+};
+
+static const struct attribute_group max16065_min_group = {
+	.attrs = max16065_min_attributes,
+	.is_visible = max16065_secondary_is_visible,
+};
+
+static const struct attribute_group max16065_max_group = {
+	.attrs = max16065_max_attributes,
+	.is_visible = max16065_secondary_is_visible,
+};
+
+static int max16065_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct max16065_data *data;
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	int i, j, val;
+	bool have_secondary;		/* true if chip has secondary limits */
+	bool secondary_is_max = false;	/* secondary limits reflect max */
+	int groups = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+				     | I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (unlikely(!data))
+		return -ENOMEM;
+
+	data->client = client;
+	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))
+			return val;
+		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))
+			return val;
+		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))
+				return val;
+			data->limit[i][j] = LIMIT_TO_MV(val, data->range[j]);
+		}
+	}
+
+	/* sysfs hooks */
+	data->groups[groups++] = &max16065_basic_group;
+	if (have_secondary)
+		data->groups[groups++] = secondary_is_max ?
+			&max16065_max_group : &max16065_min_group;
+
+	if (data->have_current) {
+		val = i2c_smbus_read_byte_data(client, MAX16065_CURR_CONTROL);
+		if (unlikely(val < 0))
+			return val;
+		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];
+			data->groups[groups++] = &max16065_current_group;
+		} else {
+			data->have_current = false;
+		}
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+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,
+	.id_table = max16065_id,
+};
+
+module_i2c_driver(max16065_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("MAX16065 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
new file mode 100644
index 0000000..eda9cf5
--- /dev/null
+++ b/drivers/hwmon/max1619.c
@@ -0,0 +1,321 @@
+/*
+ * max1619.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring
+ * Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>
+ *                         Jean Delvare <jdelvare@suse.de>
+ *
+ * Based on the lm90 driver. The MAX1619 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://pdfserv.maxim-ic.com/en/ds/MAX1619.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.
+ */
+
+#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[] = {
+	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/*
+ * The MAX1619 registers
+ */
+
+#define MAX1619_REG_R_MAN_ID		0xFE
+#define MAX1619_REG_R_CHIP_ID		0xFF
+#define MAX1619_REG_R_CONFIG		0x03
+#define MAX1619_REG_W_CONFIG		0x09
+#define MAX1619_REG_R_CONVRATE		0x04
+#define MAX1619_REG_W_CONVRATE		0x0A
+#define MAX1619_REG_R_STATUS		0x02
+#define MAX1619_REG_R_LOCAL_TEMP	0x00
+#define MAX1619_REG_R_REMOTE_TEMP	0x01
+#define MAX1619_REG_R_REMOTE_HIGH	0x07
+#define MAX1619_REG_W_REMOTE_HIGH	0x0D
+#define MAX1619_REG_R_REMOTE_LOW	0x08
+#define MAX1619_REG_W_REMOTE_LOW	0x0E
+#define MAX1619_REG_R_REMOTE_CRIT	0x10
+#define MAX1619_REG_W_REMOTE_CRIT	0x12
+#define MAX1619_REG_R_TCRIT_HYST	0x11
+#define MAX1619_REG_W_TCRIT_HYST	0x13
+
+/*
+ * Conversions
+ */
+
+static int temp_from_reg(int val)
+{
+	return (val & 0x80 ? val-0x100 : val) * 1000;
+}
+
+static int temp_to_reg(int val)
+{
+	return (val < 0 ? val+0x100*1000 : val) / 1000;
+}
+
+enum temp_index {
+	t_input1 = 0,
+	t_input2,
+	t_low2,
+	t_high2,
+	t_crit2,
+	t_hyst2,
+	t_num_regs
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max1619_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	u8 temp[t_num_regs];	/* index with enum temp_index */
+	u8 alarms;
+};
+
+static const u8 regs_read[t_num_regs] = {
+	[t_input1] = MAX1619_REG_R_LOCAL_TEMP,
+	[t_input2] = MAX1619_REG_R_REMOTE_TEMP,
+	[t_low2] = MAX1619_REG_R_REMOTE_LOW,
+	[t_high2] = MAX1619_REG_R_REMOTE_HIGH,
+	[t_crit2] = MAX1619_REG_R_REMOTE_CRIT,
+	[t_hyst2] = MAX1619_REG_R_TCRIT_HYST,
+};
+
+static const u8 regs_write[t_num_regs] = {
+	[t_low2] = MAX1619_REG_W_REMOTE_LOW,
+	[t_high2] = MAX1619_REG_W_REMOTE_HIGH,
+	[t_crit2] = MAX1619_REG_W_REMOTE_CRIT,
+	[t_hyst2] = MAX1619_REG_W_TCRIT_HYST,
+};
+
+static struct max1619_data *max1619_update_device(struct device *dev)
+{
+	struct max1619_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int config, i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+		dev_dbg(&client->dev, "Updating max1619 data.\n");
+		for (i = 0; i < t_num_regs; i++)
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+					regs_read[i]);
+		data->alarms = i2c_smbus_read_byte_data(client,
+					MAX1619_REG_R_STATUS);
+		/* If OVERT polarity is low, reverse alarm bit */
+		config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
+		if (!(config & 0x20))
+			data->alarms ^= 0x02;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+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 max1619_data *data = max1619_update_device(dev);
+
+	return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max1619_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[attr->index] = temp_to_reg(val);
+	i2c_smbus_write_byte_data(client, regs_write[attr->index],
+				  data->temp[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct max1619_data *data = max1619_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct max1619_data *data = max1619_update_device(dev);
+	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, t_input2);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_low2);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_high2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+			  t_crit2);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp,
+			  set_temp, t_hyst2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+static struct attribute *max1619_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(max1619);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max1619_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u8 reg_config, reg_convrate, reg_status, man_id, chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* detection */
+	reg_config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
+	reg_convrate = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONVRATE);
+	reg_status = i2c_smbus_read_byte_data(client, MAX1619_REG_R_STATUS);
+	if ((reg_config & 0x03) != 0x00
+	 || reg_convrate > 0x07 || (reg_status & 0x61) != 0x00) {
+		dev_dbg(&adapter->dev, "MAX1619 detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	/* identification */
+	man_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_MAN_ID);
+	chip_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CHIP_ID);
+	if (man_id != 0x4D || chip_id != 0x04) {
+		dev_info(&adapter->dev,
+			 "Unsupported chip (man_id=0x%02X, chip_id=0x%02X).\n",
+			 man_id, chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "max1619", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void max1619_init_client(struct i2c_client *client)
+{
+	u8 config;
+
+	/*
+	 * Start the conversions.
+	 */
+	i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE,
+				  5); /* 2 Hz */
+	config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
+	if (config & 0x40)
+		i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG,
+					  config & 0xBF); /* run */
+}
+
+static int max1619_probe(struct i2c_client *new_client,
+			 const struct i2c_device_id *id)
+{
+	struct max1619_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = new_client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the MAX1619 chip */
+	max1619_init_client(new_client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+							   new_client->name,
+							   data,
+							   max1619_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max1619_id[] = {
+	{ "max1619", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max1619_id);
+
+static struct i2c_driver max1619_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "max1619",
+	},
+	.probe		= max1619_probe,
+	.id_table	= max1619_id,
+	.detect		= max1619_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(max1619_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <bug-track@fisher-privat.net>, Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("MAX1619 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
new file mode 100644
index 0000000..7ca8899
--- /dev/null
+++ b/drivers/hwmon/max1668.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2011 David George <david.george@ska.ac.za>
+ *
+ * based on adm1021.c
+ * some credit to Christoph Scheurer, but largely a rewrite
+ *
+ * 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>
+
+/* Addresses to scan */
+static const unsigned short max1668_addr_list[] = {
+	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* max1668 registers */
+
+#define MAX1668_REG_TEMP(nr)	(nr)
+#define MAX1668_REG_STAT1	0x05
+#define MAX1668_REG_STAT2	0x06
+#define MAX1668_REG_MAN_ID	0xfe
+#define MAX1668_REG_DEV_ID	0xff
+
+/* limits */
+
+/* write high limits */
+#define MAX1668_REG_LIMH_WR(nr)	(0x13 + 2 * (nr))
+/* write low limits */
+#define MAX1668_REG_LIML_WR(nr)	(0x14 + 2 * (nr))
+/* read high limits */
+#define MAX1668_REG_LIMH_RD(nr)	(0x08 + 2 * (nr))
+/* read low limits */
+#define MAX1668_REG_LIML_RD(nr)	(0x09 + 2 * (nr))
+
+/* manufacturer and device ID Constants */
+#define MAN_ID_MAXIM		0x4d
+#define DEV_ID_MAX1668		0x3
+#define DEV_ID_MAX1805		0x5
+#define DEV_ID_MAX1989		0xb
+
+/* read only mode module parameter */
+static bool read_only;
+module_param(read_only, bool, 0);
+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
+
+enum chips { max1668, max1805, max1989 };
+
+struct max1668_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	enum chips type;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* 1x local and 4x remote */
+	s8 temp_max[5];
+	s8 temp_min[5];
+	s8 temp[5];
+	u16 alarms;
+};
+
+static struct max1668_data *max1668_update_device(struct device *dev)
+{
+	struct max1668_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct max1668_data *ret = data;
+	s32 val;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->valid && !time_after(jiffies,
+			data->last_updated + HZ + HZ / 2))
+		goto abort;
+
+	for (i = 0; i < 5; i++) {
+		val = i2c_smbus_read_byte_data(client, MAX1668_REG_TEMP(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp[i] = (s8) val;
+
+		val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIMH_RD(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp_max[i] = (s8) val;
+
+		val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIML_RD(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp_min[i] = (s8) val;
+	}
+
+	val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT1);
+	if (unlikely(val < 0)) {
+		ret = ERR_PTR(val);
+		goto abort;
+	}
+	data->alarms = val << 8;
+
+	val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT2);
+	if (unlikely(val < 0)) {
+		ret = ERR_PTR(val);
+		goto abort;
+	}
+	data->alarms |= val;
+
+	data->last_updated = jiffies;
+	data->valid = 1;
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = max1668_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->temp[index] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = max1668_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->temp_max[index] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = max1668_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->temp_min[index] * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct max1668_data *data = max1668_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t show_fault(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = max1668_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%u\n",
+		       (data->alarms & (1 << 12)) && data->temp[index] == 127);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[index] = clamp_val(temp/1000, -128, 127);
+	ret = i2c_smbus_write_byte_data(client,
+					MAX1668_REG_LIMH_WR(index),
+					data->temp_max[index]);
+	if (ret < 0)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max1668_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[index] = clamp_val(temp/1000, -128, 127);
+	ret = i2c_smbus_write_byte_data(client,
+					MAX1668_REG_LIML_WR(index),
+					data->temp_min[index]);
+	if (ret < 0)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max,
+				set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min,
+				set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max,
+				set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min,
+				set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max,
+				set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min,
+				set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max,
+				set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min,
+				set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max,
+				set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min,
+				set_temp_min, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 0);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_fault, NULL, 4);
+
+/* Attributes common to MAX1668, MAX1989 and MAX1805 */
+static struct attribute *max1668_attribute_common[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	NULL
+};
+
+/* Attributes not present on MAX1805 */
+static struct attribute *max1668_attribute_unique[] = {
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_min.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp5_fault.dev_attr.attr,
+	NULL
+};
+
+static umode_t max1668_attribute_mode(struct kobject *kobj,
+				     struct attribute *attr, int index)
+{
+	umode_t ret = S_IRUGO;
+	if (read_only)
+		return ret;
+	if (attr == &sensor_dev_attr_temp1_max.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp2_max.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp3_max.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp4_max.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp5_max.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp2_min.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp3_min.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp4_min.dev_attr.attr ||
+	    attr == &sensor_dev_attr_temp5_min.dev_attr.attr)
+		ret |= S_IWUSR;
+	return ret;
+}
+
+static const struct attribute_group max1668_group_common = {
+	.attrs = max1668_attribute_common,
+	.is_visible = max1668_attribute_mode
+};
+
+static const struct attribute_group max1668_group_unique = {
+	.attrs = max1668_attribute_unique,
+	.is_visible = max1668_attribute_mode
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max1668_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	const char *type_name;
+	int man_id, dev_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Check for unsupported part */
+	man_id = i2c_smbus_read_byte_data(client, MAX1668_REG_MAN_ID);
+	if (man_id != MAN_ID_MAXIM)
+		return -ENODEV;
+
+	dev_id = i2c_smbus_read_byte_data(client, MAX1668_REG_DEV_ID);
+	if (dev_id < 0)
+		return -ENODEV;
+
+	type_name = NULL;
+	if (dev_id == DEV_ID_MAX1668)
+		type_name = "max1668";
+	else if (dev_id == DEV_ID_MAX1805)
+		type_name = "max1805";
+	else if (dev_id == DEV_ID_MAX1989)
+		type_name = "max1989";
+
+	if (!type_name)
+		return -ENODEV;
+
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int max1668_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct max1668_data *data;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->type = id->driver_data;
+	mutex_init(&data->update_lock);
+
+	/* sysfs hooks */
+	data->groups[0] = &max1668_group_common;
+	if (data->type == max1668 || data->type == max1989)
+		data->groups[1] = &max1668_group_unique;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max1668_id[] = {
+	{ "max1668", max1668 },
+	{ "max1805", max1805 },
+	{ "max1989", max1989 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max1668_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max1668_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		  .name	= "max1668",
+		  },
+	.probe = max1668_probe,
+	.id_table = max1668_id,
+	.detect	= max1668_detect,
+	.address_list = max1668_addr_list,
+};
+
+module_i2c_driver(max1668_driver);
+
+MODULE_AUTHOR("David George <david.george@ska.ac.za>");
+MODULE_DESCRIPTION("MAX1668 remote temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
new file mode 100644
index 0000000..0762856
--- /dev/null
+++ b/drivers/hwmon/max197.c
@@ -0,0 +1,346 @@
+/*
+ * Maxim MAX197 A/D Converter driver
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * 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/max197 file.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/max197.h>
+
+#define MAX199_LIMIT	4000		/* 4V */
+#define MAX197_LIMIT	10000		/* 10V */
+
+#define MAX197_NUM_CH	8		/* 8 Analog Input Channels */
+
+/* Control byte format */
+#define MAX197_BIP	(1 << 3)	/* Bipolarity */
+#define MAX197_RNG	(1 << 4)	/* Full range */
+
+#define MAX197_SCALE	12207		/* Scale coefficient for raw data */
+
+/* List of supported chips */
+enum max197_chips { max197, max199 };
+
+/**
+ * struct max197_data - device instance specific data
+ * @pdata:		Platform data.
+ * @hwmon_dev:		The hwmon device.
+ * @lock:		Read/Write mutex.
+ * @limit:		Max range value (10V for MAX197, 4V for MAX199).
+ * @scale:		Need to scale.
+ * @ctrl_bytes:		Channels control byte.
+ */
+struct max197_data {
+	struct max197_platform_data *pdata;
+	struct device *hwmon_dev;
+	struct mutex lock;
+	int limit;
+	bool scale;
+	u8 ctrl_bytes[MAX197_NUM_CH];
+};
+
+static inline void max197_set_unipolarity(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] &= ~MAX197_BIP;
+}
+
+static inline void max197_set_bipolarity(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] |= MAX197_BIP;
+}
+
+static inline void max197_set_half_range(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] &= ~MAX197_RNG;
+}
+
+static inline void max197_set_full_range(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] |= MAX197_RNG;
+}
+
+static inline bool max197_is_bipolar(struct max197_data *data, int channel)
+{
+	return data->ctrl_bytes[channel] & MAX197_BIP;
+}
+
+static inline bool max197_is_full_range(struct max197_data *data, int channel)
+{
+	return data->ctrl_bytes[channel] & MAX197_RNG;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_show_range(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int channel = attr->index;
+	bool is_min = attr->nr;
+	int range;
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	range = max197_is_full_range(data, channel) ?
+		data->limit : data->limit / 2;
+	if (is_min) {
+		if (max197_is_bipolar(data, channel))
+			range = -range;
+		else
+			range = 0;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return sprintf(buf, "%d\n", range);
+}
+
+/* Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_store_range(struct device *dev,
+				  struct device_attribute *devattr,
+				  const char *buf, size_t count)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int channel = attr->index;
+	bool is_min = attr->nr;
+	long value;
+	int half = data->limit / 2;
+	int full = data->limit;
+
+	if (kstrtol(buf, 10, &value))
+		return -EINVAL;
+
+	if (is_min) {
+		if (value <= -full)
+			value = -full;
+		else if (value < 0)
+			value = -half;
+		else
+			value = 0;
+	} else {
+		if (value >= full)
+			value = full;
+		else
+			value = half;
+	}
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	if (value == 0) {
+		/* We can deduce only the polarity */
+		max197_set_unipolarity(data, channel);
+	} else if (value == -half) {
+		max197_set_bipolarity(data, channel);
+		max197_set_half_range(data, channel);
+	} else if (value == -full) {
+		max197_set_bipolarity(data, channel);
+		max197_set_full_range(data, channel);
+	} else if (value == half) {
+		/* We can deduce only the range */
+		max197_set_half_range(data, channel);
+	} else if (value == full) {
+		/* We can deduce only the range */
+		max197_set_full_range(data, channel);
+	}
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_input */
+static ssize_t max197_show_input(struct device *dev,
+				 struct device_attribute *devattr,
+				 char *buf)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int channel = attr->index;
+	s32 value;
+	int ret;
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	ret = data->pdata->convert(data->ctrl_bytes[channel]);
+	if (ret < 0) {
+		dev_err(dev, "conversion failed\n");
+		goto unlock;
+	}
+	value = ret;
+
+	/*
+	 * Coefficient to apply on raw value.
+	 * See Table 1. Full Scale and Zero Scale in the MAX197 datasheet.
+	 */
+	if (data->scale) {
+		value *= MAX197_SCALE;
+		if (max197_is_full_range(data, channel))
+			value *= 2;
+		value /= 10000;
+	}
+
+	ret = sprintf(buf, "%d\n", value);
+
+unlock:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+static ssize_t max197_show_name(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	return sprintf(buf, "%s\n", pdev->name);
+}
+
+#define MAX197_SENSOR_DEVICE_ATTR_CH(chan)				\
+	static SENSOR_DEVICE_ATTR(in##chan##_input, S_IRUGO,		\
+				  max197_show_input, NULL, chan);	\
+	static SENSOR_DEVICE_ATTR_2(in##chan##_min, S_IRUGO | S_IWUSR,	\
+				    max197_show_range,			\
+				    max197_store_range,			\
+				    true, chan);			\
+	static SENSOR_DEVICE_ATTR_2(in##chan##_max, S_IRUGO | S_IWUSR,	\
+				    max197_show_range,			\
+				    max197_store_range,			\
+				    false, chan)
+
+#define MAX197_SENSOR_DEV_ATTR_IN(chan)					\
+	&sensor_dev_attr_in##chan##_input.dev_attr.attr,		\
+	&sensor_dev_attr_in##chan##_max.dev_attr.attr,			\
+	&sensor_dev_attr_in##chan##_min.dev_attr.attr
+
+static DEVICE_ATTR(name, S_IRUGO, max197_show_name, NULL);
+
+MAX197_SENSOR_DEVICE_ATTR_CH(0);
+MAX197_SENSOR_DEVICE_ATTR_CH(1);
+MAX197_SENSOR_DEVICE_ATTR_CH(2);
+MAX197_SENSOR_DEVICE_ATTR_CH(3);
+MAX197_SENSOR_DEVICE_ATTR_CH(4);
+MAX197_SENSOR_DEVICE_ATTR_CH(5);
+MAX197_SENSOR_DEVICE_ATTR_CH(6);
+MAX197_SENSOR_DEVICE_ATTR_CH(7);
+
+static const struct attribute_group max197_sysfs_group = {
+	.attrs = (struct attribute *[]) {
+		&dev_attr_name.attr,
+		MAX197_SENSOR_DEV_ATTR_IN(0),
+		MAX197_SENSOR_DEV_ATTR_IN(1),
+		MAX197_SENSOR_DEV_ATTR_IN(2),
+		MAX197_SENSOR_DEV_ATTR_IN(3),
+		MAX197_SENSOR_DEV_ATTR_IN(4),
+		MAX197_SENSOR_DEV_ATTR_IN(5),
+		MAX197_SENSOR_DEV_ATTR_IN(6),
+		MAX197_SENSOR_DEV_ATTR_IN(7),
+		NULL
+	},
+};
+
+static int max197_probe(struct platform_device *pdev)
+{
+	int ch, ret;
+	struct max197_data *data;
+	struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+
+	if (pdata->convert == NULL) {
+		dev_err(&pdev->dev, "no convert function supplied\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->pdata = pdata;
+	mutex_init(&data->lock);
+
+	if (chip == max197) {
+		data->limit = MAX197_LIMIT;
+		data->scale = true;
+	} else {
+		data->limit = MAX199_LIMIT;
+		data->scale = false;
+	}
+
+	for (ch = 0; ch < MAX197_NUM_CH; ch++)
+		data->ctrl_bytes[ch] = (u8) ch;
+
+	platform_set_drvdata(pdev, data);
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &max197_sysfs_group);
+	if (ret) {
+		dev_err(&pdev->dev, "sysfs create group failed\n");
+		return ret;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		dev_err(&pdev->dev, "hwmon device register failed\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+	return ret;
+}
+
+static int max197_remove(struct platform_device *pdev)
+{
+	struct max197_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+
+	return 0;
+}
+
+static const struct platform_device_id max197_device_ids[] = {
+	{ "max197", max197 },
+	{ "max199", max199 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max197_device_ids);
+
+static struct platform_driver max197_driver = {
+	.driver = {
+		.name = "max197",
+	},
+	.probe = max197_probe,
+	.remove = max197_remove,
+	.id_table = max197_device_ids,
+};
+module_platform_driver(max197_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");
diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c
new file mode 100644
index 0000000..69c0ac8
--- /dev/null
+++ b/drivers/hwmon/max31790.c
@@ -0,0 +1,603 @@
+/*
+ * max31790.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring.
+ *
+ * (C) 2015 by Il Han <corone.il.han@gmail.com>
+ *
+ * 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/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/* MAX31790 registers */
+#define MAX31790_REG_GLOBAL_CONFIG	0x00
+#define MAX31790_REG_FAN_CONFIG(ch)	(0x02 + (ch))
+#define MAX31790_REG_FAN_DYNAMICS(ch)	(0x08 + (ch))
+#define MAX31790_REG_FAN_FAULT_STATUS2	0x10
+#define MAX31790_REG_FAN_FAULT_STATUS1	0x11
+#define MAX31790_REG_TACH_COUNT(ch)	(0x18 + (ch) * 2)
+#define MAX31790_REG_PWM_DUTY_CYCLE(ch)	(0x30 + (ch) * 2)
+#define MAX31790_REG_PWMOUT(ch)		(0x40 + (ch) * 2)
+#define MAX31790_REG_TARGET_COUNT(ch)	(0x50 + (ch) * 2)
+
+/* Fan Config register bits */
+#define MAX31790_FAN_CFG_RPM_MODE	0x80
+#define MAX31790_FAN_CFG_TACH_INPUT_EN	0x08
+#define MAX31790_FAN_CFG_TACH_INPUT	0x01
+
+/* Fan Dynamics register bits */
+#define MAX31790_FAN_DYN_SR_SHIFT	5
+#define MAX31790_FAN_DYN_SR_MASK	0xE0
+#define SR_FROM_REG(reg)		(((reg) & MAX31790_FAN_DYN_SR_MASK) \
+					 >> MAX31790_FAN_DYN_SR_SHIFT)
+
+#define FAN_RPM_MIN			120
+#define FAN_RPM_MAX			7864320
+
+#define RPM_FROM_REG(reg, sr)		(((reg) >> 4) ? \
+					 ((60 * (sr) * 8192) / ((reg) >> 4)) : \
+					 FAN_RPM_MAX)
+#define RPM_TO_REG(rpm, sr)		((60 * (sr) * 8192) / ((rpm) * 2))
+
+#define NR_CHANNEL			6
+
+/*
+ * Client data (each client gets its own)
+ */
+struct max31790_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	bool valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	u8 fan_config[NR_CHANNEL];
+	u8 fan_dynamics[NR_CHANNEL];
+	u16 fault_status;
+	u16 tach[NR_CHANNEL * 2];
+	u16 pwm[NR_CHANNEL];
+	u16 target_count[NR_CHANNEL];
+};
+
+static struct max31790_data *max31790_update_device(struct device *dev)
+{
+	struct max31790_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct max31790_data *ret = data;
+	int i;
+	int rv;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		rv = i2c_smbus_read_byte_data(client,
+				MAX31790_REG_FAN_FAULT_STATUS1);
+		if (rv < 0)
+			goto abort;
+		data->fault_status = rv & 0x3F;
+
+		rv = i2c_smbus_read_byte_data(client,
+				MAX31790_REG_FAN_FAULT_STATUS2);
+		if (rv < 0)
+			goto abort;
+		data->fault_status |= (rv & 0x3F) << 6;
+
+		for (i = 0; i < NR_CHANNEL; i++) {
+			rv = i2c_smbus_read_word_swapped(client,
+					MAX31790_REG_TACH_COUNT(i));
+			if (rv < 0)
+				goto abort;
+			data->tach[i] = rv;
+
+			if (data->fan_config[i]
+			    & MAX31790_FAN_CFG_TACH_INPUT) {
+				rv = i2c_smbus_read_word_swapped(client,
+					MAX31790_REG_TACH_COUNT(NR_CHANNEL
+								+ i));
+				if (rv < 0)
+					goto abort;
+				data->tach[NR_CHANNEL + i] = rv;
+			} else {
+				rv = i2c_smbus_read_word_swapped(client,
+						MAX31790_REG_PWMOUT(i));
+				if (rv < 0)
+					goto abort;
+				data->pwm[i] = rv;
+
+				rv = i2c_smbus_read_word_swapped(client,
+						MAX31790_REG_TARGET_COUNT(i));
+				if (rv < 0)
+					goto abort;
+				data->target_count[i] = rv;
+			}
+		}
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+	goto done;
+
+abort:
+	data->valid = false;
+	ret = ERR_PTR(rv);
+
+done:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 };
+
+static u8 get_tach_period(u8 fan_dynamics)
+{
+	return tach_period[SR_FROM_REG(fan_dynamics)];
+}
+
+static u8 bits_for_tach_period(int rpm)
+{
+	u8 bits;
+
+	if (rpm < 500)
+		bits = 0x0;
+	else if (rpm < 1000)
+		bits = 0x1;
+	else if (rpm < 2000)
+		bits = 0x2;
+	else if (rpm < 4000)
+		bits = 0x3;
+	else if (rpm < 8000)
+		bits = 0x4;
+	else
+		bits = 0x5;
+
+	return bits;
+}
+
+static ssize_t get_fan(struct device *dev,
+		       struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = max31790_update_device(dev);
+	int sr, rpm;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	sr = get_tach_period(data->fan_dynamics[attr->index]);
+	rpm = RPM_FROM_REG(data->tach[attr->index], sr);
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t get_fan_target(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = max31790_update_device(dev);
+	int sr, rpm;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	sr = get_tach_period(data->fan_dynamics[attr->index]);
+	rpm = RPM_FROM_REG(data->target_count[attr->index], sr);
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_target(struct device *dev,
+			      struct device_attribute *devattr,
+			      const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 bits;
+	int sr;
+	int target_count;
+	unsigned long rpm;
+	int err;
+
+	err = kstrtoul(buf, 10, &rpm);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+	bits = bits_for_tach_period(rpm);
+	data->fan_dynamics[attr->index] =
+			((data->fan_dynamics[attr->index]
+			  & ~MAX31790_FAN_DYN_SR_MASK)
+			 | (bits << MAX31790_FAN_DYN_SR_SHIFT));
+	err = i2c_smbus_write_byte_data(client,
+			MAX31790_REG_FAN_DYNAMICS(attr->index),
+			data->fan_dynamics[attr->index]);
+
+	if (err < 0) {
+		mutex_unlock(&data->update_lock);
+		return err;
+	}
+
+	sr = get_tach_period(data->fan_dynamics[attr->index]);
+	target_count = RPM_TO_REG(rpm, sr);
+	target_count = clamp_val(target_count, 0x1, 0x7FF);
+
+	data->target_count[attr->index] = target_count << 5;
+
+	err = i2c_smbus_write_word_swapped(client,
+			MAX31790_REG_TARGET_COUNT(attr->index),
+			data->target_count[attr->index]);
+
+	mutex_unlock(&data->update_lock);
+
+	if (err < 0)
+		return err;
+
+	return count;
+}
+
+static ssize_t get_pwm(struct device *dev,
+		       struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = max31790_update_device(dev);
+	int pwm;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	pwm = data->pwm[attr->index] >> 8;
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev,
+		       struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long pwm;
+	int err;
+
+	err = kstrtoul(buf, 10, &pwm);
+	if (err)
+		return err;
+
+	if (pwm > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	data->pwm[attr->index] = pwm << 8;
+	err = i2c_smbus_write_word_swapped(client,
+			MAX31790_REG_PWMOUT(attr->index),
+			data->pwm[attr->index]);
+
+	mutex_unlock(&data->update_lock);
+
+	if (err < 0)
+		return err;
+
+	return count;
+}
+
+static ssize_t get_pwm_enable(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = max31790_update_device(dev);
+	int mode;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	if (data->fan_config[attr->index] & MAX31790_FAN_CFG_RPM_MODE)
+		mode = 2;
+	else if (data->fan_config[attr->index] & MAX31790_FAN_CFG_TACH_INPUT_EN)
+		mode = 1;
+	else
+		mode = 0;
+
+	return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+			      struct device_attribute *devattr,
+			      const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long mode;
+	int err;
+
+	err = kstrtoul(buf, 10, &mode);
+	if (err)
+		return err;
+
+	switch (mode) {
+	case 0:
+		data->fan_config[attr->index] =
+			data->fan_config[attr->index]
+			& ~(MAX31790_FAN_CFG_TACH_INPUT_EN
+			    | MAX31790_FAN_CFG_RPM_MODE);
+		break;
+	case 1:
+		data->fan_config[attr->index] =
+			(data->fan_config[attr->index]
+			 | MAX31790_FAN_CFG_TACH_INPUT_EN)
+			& ~MAX31790_FAN_CFG_RPM_MODE;
+		break;
+	case 2:
+		data->fan_config[attr->index] =
+			data->fan_config[attr->index]
+			| MAX31790_FAN_CFG_TACH_INPUT_EN
+			| MAX31790_FAN_CFG_RPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+
+	err = i2c_smbus_write_byte_data(client,
+			MAX31790_REG_FAN_CONFIG(attr->index),
+			data->fan_config[attr->index]);
+
+	mutex_unlock(&data->update_lock);
+
+	if (err < 0)
+		return err;
+
+	return count;
+}
+
+static ssize_t get_fan_fault(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max31790_data *data = max31790_update_device(dev);
+	int fault;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	fault = !!(data->fault_status & (1 << attr->index));
+
+	return sprintf(buf, "%d\n", fault);
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, get_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, get_fan, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, get_fan_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, get_fan_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, get_fan_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, get_fan_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, get_fan_fault, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, get_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, get_fan, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, get_fan, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, get_fan, NULL, 9);
+static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, get_fan, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, get_fan, NULL, 11);
+
+static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, get_fan_fault, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, get_fan_fault, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan9_fault, S_IRUGO, get_fan_fault, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan10_fault, S_IRUGO, get_fan_fault, NULL, 9);
+static SENSOR_DEVICE_ATTR(fan11_fault, S_IRUGO, get_fan_fault, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan12_fault, S_IRUGO, get_fan_fault, NULL, 11);
+
+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 0);
+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 1);
+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 2);
+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 3);
+static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 4);
+static SENSOR_DEVICE_ATTR(fan6_target, S_IWUSR | S_IRUGO,
+		get_fan_target, set_fan_target, 5);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 4);
+static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 5);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 4);
+static SENSOR_DEVICE_ATTR(pwm6_enable, S_IWUSR | S_IRUGO,
+		get_pwm_enable, set_pwm_enable, 5);
+
+static struct attribute *max31790_attrs[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan3_fault.dev_attr.attr,
+	&sensor_dev_attr_fan4_fault.dev_attr.attr,
+	&sensor_dev_attr_fan5_fault.dev_attr.attr,
+	&sensor_dev_attr_fan6_fault.dev_attr.attr,
+
+	&sensor_dev_attr_fan7_input.dev_attr.attr,
+	&sensor_dev_attr_fan8_input.dev_attr.attr,
+	&sensor_dev_attr_fan9_input.dev_attr.attr,
+	&sensor_dev_attr_fan10_input.dev_attr.attr,
+	&sensor_dev_attr_fan11_input.dev_attr.attr,
+	&sensor_dev_attr_fan12_input.dev_attr.attr,
+
+	&sensor_dev_attr_fan7_fault.dev_attr.attr,
+	&sensor_dev_attr_fan8_fault.dev_attr.attr,
+	&sensor_dev_attr_fan9_fault.dev_attr.attr,
+	&sensor_dev_attr_fan10_fault.dev_attr.attr,
+	&sensor_dev_attr_fan11_fault.dev_attr.attr,
+	&sensor_dev_attr_fan12_fault.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_target.dev_attr.attr,
+	&sensor_dev_attr_fan2_target.dev_attr.attr,
+	&sensor_dev_attr_fan3_target.dev_attr.attr,
+	&sensor_dev_attr_fan4_target.dev_attr.attr,
+	&sensor_dev_attr_fan5_target.dev_attr.attr,
+	&sensor_dev_attr_fan6_target.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.attr,
+	&sensor_dev_attr_pwm5.dev_attr.attr,
+	&sensor_dev_attr_pwm6.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm5_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm6_enable.dev_attr.attr,
+	NULL
+};
+
+static umode_t max31790_attrs_visible(struct kobject *kobj,
+				     struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct max31790_data *data = dev_get_drvdata(dev);
+	struct device_attribute *devattr =
+			container_of(a, struct device_attribute, attr);
+	int index = to_sensor_dev_attr(devattr)->index % NR_CHANNEL;
+	u8 fan_config;
+
+	fan_config = data->fan_config[index];
+
+	if (n >= NR_CHANNEL * 2 && n < NR_CHANNEL * 4 &&
+	    !(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
+		return 0;
+	if (n >= NR_CHANNEL * 4 && (fan_config & MAX31790_FAN_CFG_TACH_INPUT))
+		return 0;
+
+	return a->mode;
+}
+
+static const struct attribute_group max31790_group = {
+	.attrs = max31790_attrs,
+	.is_visible = max31790_attrs_visible,
+};
+__ATTRIBUTE_GROUPS(max31790);
+
+static int max31790_init_client(struct i2c_client *client,
+				struct max31790_data *data)
+{
+	int i, rv;
+
+	for (i = 0; i < NR_CHANNEL; i++) {
+		rv = i2c_smbus_read_byte_data(client,
+				MAX31790_REG_FAN_CONFIG(i));
+		if (rv < 0)
+			return rv;
+		data->fan_config[i] = rv;
+
+		rv = i2c_smbus_read_byte_data(client,
+				MAX31790_REG_FAN_DYNAMICS(i));
+		if (rv < 0)
+			return rv;
+		data->fan_dynamics[i] = rv;
+	}
+
+	return 0;
+}
+
+static int max31790_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct max31790_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	if (!i2c_check_functionality(adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the max31790 chip
+	 */
+	err = max31790_init_client(client, data);
+	if (err)
+		return err;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+			client->name, data, max31790_groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max31790_id[] = {
+	{ "max31790", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max31790_id);
+
+static struct i2c_driver max31790_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.probe		= max31790_probe,
+	.driver = {
+		.name	= "max31790",
+	},
+	.id_table	= max31790_id,
+};
+
+module_i2c_driver(max31790_driver);
+
+MODULE_AUTHOR("Il Han <corone.il.han@gmail.com>");
+MODULE_DESCRIPTION("MAX31790 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
new file mode 100644
index 0000000..dac6d85
--- /dev/null
+++ b/drivers/hwmon/max6639.c
@@ -0,0 +1,613 @@
+/*
+ * max6639.c - Support for Maxim MAX6639
+ *
+ * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller
+ *
+ * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * based on the initial MAX6639 support from semptian.net
+ * by He Changqing <hechangqing@semptian.com>
+ *
+ * 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/i2c/max6639.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* The MAX6639 registers, valid channel numbers: 0, 1 */
+#define MAX6639_REG_TEMP(ch)			(0x00 + (ch))
+#define MAX6639_REG_STATUS			0x02
+#define MAX6639_REG_OUTPUT_MASK			0x03
+#define MAX6639_REG_GCONFIG			0x04
+#define MAX6639_REG_TEMP_EXT(ch)		(0x05 + (ch))
+#define MAX6639_REG_ALERT_LIMIT(ch)		(0x08 + (ch))
+#define MAX6639_REG_OT_LIMIT(ch)		(0x0A + (ch))
+#define MAX6639_REG_THERM_LIMIT(ch)		(0x0C + (ch))
+#define MAX6639_REG_FAN_CONFIG1(ch)		(0x10 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG2a(ch)		(0x11 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG2b(ch)		(0x12 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG3(ch)		(0x13 + (ch) * 4)
+#define MAX6639_REG_FAN_CNT(ch)			(0x20 + (ch))
+#define MAX6639_REG_TARGET_CNT(ch)		(0x22 + (ch))
+#define MAX6639_REG_FAN_PPR(ch)			(0x24 + (ch))
+#define MAX6639_REG_TARGTDUTY(ch)		(0x26 + (ch))
+#define MAX6639_REG_FAN_START_TEMP(ch)		(0x28 + (ch))
+#define MAX6639_REG_DEVID			0x3D
+#define MAX6639_REG_MANUID			0x3E
+#define MAX6639_REG_DEVREV			0x3F
+
+/* Register bits */
+#define MAX6639_GCONFIG_STANDBY			0x80
+#define MAX6639_GCONFIG_POR			0x40
+#define MAX6639_GCONFIG_DISABLE_TIMEOUT		0x20
+#define MAX6639_GCONFIG_CH2_LOCAL		0x10
+#define MAX6639_GCONFIG_PWM_FREQ_HI		0x08
+
+#define MAX6639_FAN_CONFIG1_PWM			0x80
+
+#define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED	0x40
+
+static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
+
+#define FAN_FROM_REG(val, rpm_range)	((val) == 0 || (val) == 255 ? \
+				0 : (rpm_ranges[rpm_range] * 30) / (val))
+#define TEMP_LIMIT_TO_REG(val)	clamp_val((val) / 1000, 0, 255)
+
+/*
+ * Client data (each client gets its own)
+ */
+struct max6639_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* Register values sampled regularly */
+	u16 temp[2];		/* Temperature, in 1/8 C, 0..255 C */
+	bool temp_fault[2];	/* Detected temperature diode failure */
+	u8 fan[2];		/* Register value: TACH count for fans >=30 */
+	u8 status;		/* Detected channel alarms and fan failures */
+
+	/* Register values only written to */
+	u8 pwm[2];		/* Register value: Duty cycle 0..120 */
+	u8 temp_therm[2];	/* THERM Temperature, 0..255 C (->_max) */
+	u8 temp_alert[2];	/* ALERT Temperature, 0..255 C (->_crit) */
+	u8 temp_ot[2];		/* OT Temperature, 0..255 C (->_emergency) */
+
+	/* Register values initialized only once */
+	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
+	u8 rpm_range;		/* Index in above rpm_ranges table */
+};
+
+static struct max6639_data *max6639_update_device(struct device *dev)
+{
+	struct max6639_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct max6639_data *ret = data;
+	int i;
+	int status_reg;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+		int res;
+
+		dev_dbg(&client->dev, "Starting max6639 update\n");
+
+		status_reg = i2c_smbus_read_byte_data(client,
+						      MAX6639_REG_STATUS);
+		if (status_reg < 0) {
+			ret = ERR_PTR(status_reg);
+			goto abort;
+		}
+
+		data->status = status_reg;
+
+		for (i = 0; i < 2; i++) {
+			res = i2c_smbus_read_byte_data(client,
+					MAX6639_REG_FAN_CNT(i));
+			if (res < 0) {
+				ret = ERR_PTR(res);
+				goto abort;
+			}
+			data->fan[i] = res;
+
+			res = i2c_smbus_read_byte_data(client,
+					MAX6639_REG_TEMP_EXT(i));
+			if (res < 0) {
+				ret = ERR_PTR(res);
+				goto abort;
+			}
+			data->temp[i] = res >> 5;
+			data->temp_fault[i] = res & 0x01;
+
+			res = i2c_smbus_read_byte_data(client,
+					MAX6639_REG_TEMP(i));
+			if (res < 0) {
+				ret = ERR_PTR(res);
+				goto abort;
+			}
+			data->temp[i] |= res << 3;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *dev_attr, char *buf)
+{
+	long temp;
+	struct max6639_data *data = max6639_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = data->temp[attr->index] * 125;
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+			       struct device_attribute *dev_attr, char *buf)
+{
+	struct max6639_data *data = max6639_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->temp_fault[attr->index]);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *dev_attr,
+			    const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int res;
+
+	res = kstrtoul(buf, 10, &val);
+	if (res)
+		return res;
+
+	mutex_lock(&data->update_lock);
+	data->temp_therm[attr->index] = TEMP_LIMIT_TO_REG(val);
+	i2c_smbus_write_byte_data(client,
+				  MAX6639_REG_THERM_LIMIT(attr->index),
+				  data->temp_therm[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+			      struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
+}
+
+static ssize_t set_temp_crit(struct device *dev,
+			     struct device_attribute *dev_attr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int res;
+
+	res = kstrtoul(buf, 10, &val);
+	if (res)
+		return res;
+
+	mutex_lock(&data->update_lock);
+	data->temp_alert[attr->index] = TEMP_LIMIT_TO_REG(val);
+	i2c_smbus_write_byte_data(client,
+				  MAX6639_REG_ALERT_LIMIT(attr->index),
+				  data->temp_alert[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_emergency(struct device *dev,
+				   struct device_attribute *dev_attr,
+				   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
+}
+
+static ssize_t set_temp_emergency(struct device *dev,
+				  struct device_attribute *dev_attr,
+				  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int res;
+
+	res = kstrtoul(buf, 10, &val);
+	if (res)
+		return res;
+
+	mutex_lock(&data->update_lock);
+	data->temp_ot[attr->index] = TEMP_LIMIT_TO_REG(val);
+	i2c_smbus_write_byte_data(client,
+				  MAX6639_REG_OT_LIMIT(attr->index),
+				  data->temp_ot[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
+}
+
+static ssize_t set_pwm(struct device *dev,
+		       struct device_attribute *dev_attr,
+		       const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6639_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int res;
+
+	res = kstrtoul(buf, 10, &val);
+	if (res)
+		return res;
+
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->pwm[attr->index] = (u8)(val * 120 / 255);
+	i2c_smbus_write_byte_data(client,
+				  MAX6639_REG_TARGTDUTY(attr->index),
+				  data->pwm[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan_input(struct device *dev,
+			      struct device_attribute *dev_attr, char *buf)
+{
+	struct max6639_data *data = max6639_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
+		       data->rpm_range));
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *dev_attr, char *buf)
+{
+	struct max6639_data *data = max6639_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", !!(data->status & (1 << attr->index)));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+		set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+		set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+		set_temp_crit, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+		set_temp_crit, 1);
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO,
+		show_temp_emergency, set_temp_emergency, 0);
+static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO,
+		show_temp_emergency, set_temp_emergency, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+
+static struct attribute *max6639_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(max6639);
+
+/*
+ *  returns respective index in rpm_ranges table
+ *  1 by default on invalid range
+ */
+static int rpm_range_to_reg(int range)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
+		if (rpm_ranges[i] == range)
+			return i;
+	}
+
+	return 1; /* default: 4000 RPM */
+}
+
+static int max6639_init_client(struct i2c_client *client,
+			       struct max6639_data *data)
+{
+	struct max6639_platform_data *max6639_info =
+		dev_get_platdata(&client->dev);
+	int i;
+	int rpm_range = 1; /* default: 4000 RPM */
+	int err;
+
+	/* Reset chip to default values, see below for GCONFIG setup */
+	err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
+				  MAX6639_GCONFIG_POR);
+	if (err)
+		goto exit;
+
+	/* Fans pulse per revolution is 2 by default */
+	if (max6639_info && max6639_info->ppr > 0 &&
+			max6639_info->ppr < 5)
+		data->ppr = max6639_info->ppr;
+	else
+		data->ppr = 2;
+	data->ppr -= 1;
+
+	if (max6639_info)
+		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
+	data->rpm_range = rpm_range;
+
+	for (i = 0; i < 2; i++) {
+
+		/* Set Fan pulse per revolution */
+		err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_FAN_PPR(i),
+				data->ppr << 6);
+		if (err)
+			goto exit;
+
+		/* Fans config PWM, RPM */
+		err = i2c_smbus_write_byte_data(client,
+			MAX6639_REG_FAN_CONFIG1(i),
+			MAX6639_FAN_CONFIG1_PWM | rpm_range);
+		if (err)
+			goto exit;
+
+		/* Fans PWM polarity high by default */
+		if (max6639_info && max6639_info->pwm_polarity == 0)
+			err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_FAN_CONFIG2a(i), 0x00);
+		else
+			err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_FAN_CONFIG2a(i), 0x02);
+		if (err)
+			goto exit;
+
+		/*
+		 * /THERM full speed enable,
+		 * PWM frequency 25kHz, see also GCONFIG below
+		 */
+		err = i2c_smbus_write_byte_data(client,
+			MAX6639_REG_FAN_CONFIG3(i),
+			MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
+		if (err)
+			goto exit;
+
+		/* Max. temp. 80C/90C/100C */
+		data->temp_therm[i] = 80;
+		data->temp_alert[i] = 90;
+		data->temp_ot[i] = 100;
+		err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_THERM_LIMIT(i),
+				data->temp_therm[i]);
+		if (err)
+			goto exit;
+		err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_ALERT_LIMIT(i),
+				data->temp_alert[i]);
+		if (err)
+			goto exit;
+		err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_OT_LIMIT(i), data->temp_ot[i]);
+		if (err)
+			goto exit;
+
+		/* PWM 120/120 (i.e. 100%) */
+		data->pwm[i] = 120;
+		err = i2c_smbus_write_byte_data(client,
+				MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
+		if (err)
+			goto exit;
+	}
+	/* Start monitoring */
+	err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
+		MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
+		MAX6639_GCONFIG_PWM_FREQ_HI);
+exit:
+	return err;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6639_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int dev_id, manu_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Actual detection via device and manufacturer ID */
+	dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
+	manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
+	if (dev_id != 0x58 || manu_id != 0x4D)
+		return -ENODEV;
+
+	strlcpy(info->type, "max6639", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int max6639_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct max6639_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the max6639 chip */
+	err = max6639_init_client(client, data);
+	if (err < 0)
+		return err;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   max6639_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max6639_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+	if (data < 0)
+		return data;
+
+	return i2c_smbus_write_byte_data(client,
+			MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
+}
+
+static int max6639_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+	if (data < 0)
+		return data;
+
+	return i2c_smbus_write_byte_data(client,
+			MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct i2c_device_id max6639_id[] = {
+	{"max6639", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, max6639_id);
+
+static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
+
+static struct i2c_driver max6639_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		   .name = "max6639",
+		   .pm = &max6639_pm_ops,
+		   },
+	.probe = max6639_probe,
+	.id_table = max6639_id,
+	.detect = max6639_detect,
+	.address_list = normal_i2c,
+};
+
+module_i2c_driver(max6639_driver);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("max6639 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
new file mode 100644
index 0000000..6520bc5
--- /dev/null
+++ b/drivers/hwmon/max6642.c
@@ -0,0 +1,327 @@
+/*
+ * 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 Oleksij Rempel <bug-track@fisher-privat.net>
+ *                          Jean Delvare <jdelvare@suse.de>
+ *
+ * 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 i2c_client *client;
+	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 max6642_data *data,
+				struct i2c_client *client)
+{
+	u8 config;
+
+	/*
+	 * 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;
+
+	/* sanity check */
+	if (i2c_smbus_read_byte_data(client, 0x04) != 0x4D
+	    || i2c_smbus_read_byte_data(client, 0x06) != 0x4D
+	    || i2c_smbus_read_byte_data(client, 0xff) != 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);
+	if ((reg_config & 0x0f) != 0x00)
+		return -ENODEV;
+
+	/* in between, another round of sanity checks */
+	if (i2c_smbus_read_byte_data(client, 0x04) != reg_config
+	    || i2c_smbus_read_byte_data(client, 0x06) != reg_config
+	    || i2c_smbus_read_byte_data(client, 0xff) != reg_config)
+		return -ENODEV;
+
+	reg_status = i2c_smbus_read_byte_data(client, MAX6642_REG_R_STATUS);
+	if ((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 max6642_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u16 val, tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		dev_dbg(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 sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct max6642_data *data = max6642_update_device(dev);
+
+	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 sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+	struct max6642_data *data = max6642_update_device(dev);
+
+	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)
+{
+	struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+	struct max6642_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255);
+	i2c_smbus_write_byte_data(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(temp2_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_attrs[] = {
+	&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_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(max6642);
+
+static int max6642_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct max6642_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct max6642_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the MAX6642 chip */
+	max6642_init_client(data, client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   max6642_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * 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,
+	.id_table	= max6642_id,
+	.detect		= max6642_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(max6642_driver);
+
+MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
+MODULE_DESCRIPTION("MAX6642 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
new file mode 100644
index 0000000..162a520
--- /dev/null
+++ b/drivers/hwmon/max6650.c
@@ -0,0 +1,703 @@
+/*
+ * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring.
+ *
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
+ *
+ * based on code written by John Morris <john.morris@spirentcom.com>
+ * Copyright (c) 2003 Spirent Communications
+ * and Claus Gindhart <claus.gindhart@kontron.com>
+ *
+ * This module has only been tested with the MAX6650 chip. It should
+ * also work with the MAX6651. It does not distinguish max6650 and max6651
+ * chips.
+ *
+ * The datasheet was last seen at:
+ *
+ *        http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.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>
+
+/*
+ * Insmod parameters
+ */
+
+/* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */
+static int fan_voltage;
+/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */
+static int prescaler;
+/* clock: The clock frequency of the chip the driver should assume */
+static int clock = 254000;
+
+module_param(fan_voltage, int, S_IRUGO);
+module_param(prescaler, int, S_IRUGO);
+module_param(clock, int, S_IRUGO);
+
+/*
+ * MAX 6650/6651 registers
+ */
+
+#define MAX6650_REG_SPEED	0x00
+#define MAX6650_REG_CONFIG	0x02
+#define MAX6650_REG_GPIO_DEF	0x04
+#define MAX6650_REG_DAC		0x06
+#define MAX6650_REG_ALARM_EN	0x08
+#define MAX6650_REG_ALARM	0x0A
+#define MAX6650_REG_TACH0	0x0C
+#define MAX6650_REG_TACH1	0x0E
+#define MAX6650_REG_TACH2	0x10
+#define MAX6650_REG_TACH3	0x12
+#define MAX6650_REG_GPIO_STAT	0x14
+#define MAX6650_REG_COUNT	0x16
+
+/*
+ * Config register bits
+ */
+
+#define MAX6650_CFG_V12			0x08
+#define MAX6650_CFG_PRESCALER_MASK	0x07
+#define MAX6650_CFG_PRESCALER_2		0x01
+#define MAX6650_CFG_PRESCALER_4		0x02
+#define MAX6650_CFG_PRESCALER_8		0x03
+#define MAX6650_CFG_PRESCALER_16	0x04
+#define MAX6650_CFG_MODE_MASK		0x30
+#define MAX6650_CFG_MODE_ON		0x00
+#define MAX6650_CFG_MODE_OFF		0x10
+#define MAX6650_CFG_MODE_CLOSED_LOOP	0x20
+#define MAX6650_CFG_MODE_OPEN_LOOP	0x30
+#define MAX6650_COUNT_MASK		0x03
+
+/*
+ * Alarm status register bits
+ */
+
+#define MAX6650_ALRM_MAX	0x01
+#define MAX6650_ALRM_MIN	0x02
+#define MAX6650_ALRM_TACH	0x04
+#define MAX6650_ALRM_GPIO1	0x08
+#define MAX6650_ALRM_GPIO2	0x10
+
+/* Minimum and maximum values of the FAN-RPM */
+#define FAN_RPM_MIN 240
+#define FAN_RPM_MAX 30000
+
+#define DIV_FROM_REG(reg) (1 << (reg & 7))
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max6650_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	int nr_fans;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	u8 speed;
+	u8 config;
+	u8 tach[4];
+	u8 count;
+	u8 dac;
+	u8 alarm;
+};
+
+static const u8 tach_reg[] = {
+	MAX6650_REG_TACH0,
+	MAX6650_REG_TACH1,
+	MAX6650_REG_TACH2,
+	MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		data->speed = i2c_smbus_read_byte_data(client,
+						       MAX6650_REG_SPEED);
+		data->config = i2c_smbus_read_byte_data(client,
+							MAX6650_REG_CONFIG);
+		for (i = 0; i < data->nr_fans; i++) {
+			data->tach[i] = i2c_smbus_read_byte_data(client,
+								 tach_reg[i]);
+		}
+		data->count = i2c_smbus_read_byte_data(client,
+							MAX6650_REG_COUNT);
+		data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+		/*
+		 * Alarms are cleared on read in case the condition that
+		 * caused the alarm is removed. Keep the value latched here
+		 * for providing the register through different alarm files.
+		 */
+		data->alarm |= i2c_smbus_read_byte_data(client,
+							MAX6650_REG_ALARM);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max6650_data *data = max6650_update_device(dev);
+	int rpm;
+
+	/*
+	 * Calculation details:
+	 *
+	 * Each tachometer counts over an interval given by the "count"
+	 * register (0.25, 0.5, 1 or 2 seconds). This module assumes
+	 * that the fans produce two pulses per revolution (this seems
+	 * to be the most common).
+	 */
+
+	rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
+	return sprintf(buf, "%d\n", rpm);
+}
+
+/*
+ * Set the fan speed to the specified RPM (or read back the RPM setting).
+ * This works in closed loop mode only. Use pwm1 for open loop speed setting.
+ *
+ * The MAX6650/1 will automatically control fan speed when in closed loop
+ * mode.
+ *
+ * Assumptions:
+ *
+ * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use
+ *    the clock module parameter if you need to fine tune this.
+ *
+ * 2) The prescaler (low three bits of the config register) has already
+ *    been set to an appropriate value. Use the prescaler module parameter
+ *    if your BIOS doesn't initialize the chip properly.
+ *
+ * The relevant equations are given on pages 21 and 22 of the datasheet.
+ *
+ * From the datasheet, the relevant equation when in regulation is:
+ *
+ *    [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE
+ *
+ * where:
+ *
+ *    fCLK is the oscillator frequency (either the 254kHz internal
+ *         oscillator or the externally applied clock)
+ *
+ *    KTACH is the value in the speed register
+ *
+ *    FanSpeed is the speed of the fan in rps
+ *
+ *    KSCALE is the prescaler value (1, 2, 4, 8, or 16)
+ *
+ * When reading, we need to solve for FanSpeed. When writing, we need to
+ * solve for KTACH.
+ *
+ * Note: this tachometer is completely separate from the tachometers
+ * used to measure the fan speeds. Only one fan's speed (fan1) is
+ * controlled.
+ */
+
+static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+	int kscale, ktach, rpm;
+
+	/*
+	 * Use the datasheet equation:
+	 *
+	 *    FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
+	 *
+	 * then multiply by 60 to give rpm.
+	 */
+
+	kscale = DIV_FROM_REG(data->config);
+	ktach = data->speed;
+	rpm = 60 * kscale * clock / (256 * (ktach + 1));
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int kscale, ktach;
+	unsigned long rpm;
+	int err;
+
+	err = kstrtoul(buf, 10, &rpm);
+	if (err)
+		return err;
+
+	rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+
+	/*
+	 * Divide the required speed by 60 to get from rpm to rps, then
+	 * use the datasheet equation:
+	 *
+	 *     KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
+	 */
+
+	mutex_lock(&data->update_lock);
+
+	kscale = DIV_FROM_REG(data->config);
+	ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;
+	if (ktach < 0)
+		ktach = 0;
+	if (ktach > 255)
+		ktach = 255;
+	data->speed = ktach;
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_SPEED, data->speed);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Get/set the fan speed in open loop mode using pwm1 sysfs file.
+ * Speed is given as a relative value from 0 to 255, where 255 is maximum
+ * speed. Note that this is done by writing directly to the chip's DAC,
+ * it won't change the closed loop speed set by fan1_target.
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+
+static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	int pwm;
+	struct max6650_data *data = max6650_update_device(dev);
+
+	/*
+	 * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
+	 * Lower DAC values mean higher speeds.
+	 */
+	if (data->config & MAX6650_CFG_V12)
+		pwm = 255 - (255 * (int)data->dac)/180;
+	else
+		pwm = 255 - (255 * (int)data->dac)/76;
+
+	if (pwm < 0)
+		pwm = 0;
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long pwm;
+	int err;
+
+	err = kstrtoul(buf, 10, &pwm);
+	if (err)
+		return err;
+
+	pwm = clamp_val(pwm, 0, 255);
+
+	mutex_lock(&data->update_lock);
+
+	if (data->config & MAX6650_CFG_V12)
+		data->dac = 180 - (180 * pwm)/255;
+	else
+		data->dac = 76 - (76 * pwm)/255;
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Get/Set controller mode:
+ * Possible values:
+ * 0 = Fan always on
+ * 1 = Open loop, Voltage is set according to speed, not regulated.
+ * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
+ */
+
+static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
+			  char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+	int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
+	int sysfs_modes[4] = {0, 1, 2, 1};
+
+	return sprintf(buf, "%d\n", sysfs_modes[mode]);
+}
+
+static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int max6650_modes[3] = {0, 3, 2};
+	unsigned long mode;
+	int err;
+
+	err = kstrtoul(buf, 10, &mode);
+	if (err)
+		return err;
+
+	if (mode > 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	data->config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+	data->config = (data->config & ~MAX6650_CFG_MODE_MASK)
+		       | (max6650_modes[mode] << 4);
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
+ * divider. We handle this by converting between divider and counttime:
+ *
+ * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
+ *
+ * Lower values of k allow to connect a faster fan without the risk of
+ * counter overflow. The price is lower resolution. You can also set counttime
+ * using the module parameter. Note that the module parameter "prescaler" also
+ * influences the behaviour. Unfortunately, there's no sysfs attribute
+ * defined for that. See the data sheet for details.
+ */
+
+static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
+}
+
+static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long div;
+	int err;
+
+	err = kstrtoul(buf, 10, &div);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (div) {
+	case 1:
+		data->count = 0;
+		break;
+	case 2:
+		data->count = 1;
+		break;
+	case 4:
+		data->count = 2;
+		break;
+	case 8:
+		data->count = 3;
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Get alarm stati:
+ * Possible values:
+ * 0 = no alarm
+ * 1 = alarm
+ */
+
+static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max6650_data *data = max6650_update_device(dev);
+	struct i2c_client *client = data->client;
+	int alarm = 0;
+
+	if (data->alarm & attr->index) {
+		mutex_lock(&data->update_lock);
+		alarm = 1;
+		data->alarm &= ~attr->index;
+		data->alarm |= i2c_smbus_read_byte_data(client,
+							MAX6650_REG_ALARM);
+		mutex_unlock(&data->update_lock);
+	}
+
+	return sprintf(buf, "%d\n", alarm);
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL,
+			  MAX6650_ALRM_MAX);
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL,
+			  MAX6650_ALRM_MIN);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL,
+			  MAX6650_ALRM_TACH);
+static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL,
+			  MAX6650_ALRM_GPIO1);
+static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL,
+			  MAX6650_ALRM_GPIO2);
+
+static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
+				    int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct max6650_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
+	struct device_attribute *devattr;
+
+	/*
+	 * Hide the alarms that have not been enabled by the firmware
+	 */
+
+	devattr = container_of(a, struct device_attribute, attr);
+	if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
+	 || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
+	 || devattr == &sensor_dev_attr_fan1_fault.dev_attr
+	 || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
+	 || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
+		if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
+			return 0;
+	}
+
+	return a->mode;
+}
+
+static struct attribute *max6650_attrs[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_div.attr,
+	&dev_attr_pwm1_enable.attr,
+	&dev_attr_pwm1.attr,
+	&sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_gpio1_alarm.dev_attr.attr,
+	&sensor_dev_attr_gpio2_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max6650_group = {
+	.attrs = max6650_attrs,
+	.is_visible = max6650_attrs_visible,
+};
+
+static struct attribute *max6651_attrs[] = {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max6651_group = {
+	.attrs = max6651_attrs,
+};
+
+/*
+ * Real code
+ */
+
+static int max6650_init_client(struct max6650_data *data,
+			       struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	int config;
+	int err = -EIO;
+
+	config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+
+	if (config < 0) {
+		dev_err(dev, "Error reading config, aborting.\n");
+		return err;
+	}
+
+	switch (fan_voltage) {
+	case 0:
+		break;
+	case 5:
+		config &= ~MAX6650_CFG_V12;
+		break;
+	case 12:
+		config |= MAX6650_CFG_V12;
+		break;
+	default:
+		dev_err(dev, "illegal value for fan_voltage (%d)\n",
+			fan_voltage);
+	}
+
+	dev_info(dev, "Fan voltage is set to %dV.\n",
+		 (config & MAX6650_CFG_V12) ? 12 : 5);
+
+	switch (prescaler) {
+	case 0:
+		break;
+	case 1:
+		config &= ~MAX6650_CFG_PRESCALER_MASK;
+		break;
+	case 2:
+		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+			 | MAX6650_CFG_PRESCALER_2;
+		break;
+	case  4:
+		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+			 | MAX6650_CFG_PRESCALER_4;
+		break;
+	case  8:
+		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+			 | MAX6650_CFG_PRESCALER_8;
+		break;
+	case 16:
+		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+			 | MAX6650_CFG_PRESCALER_16;
+		break;
+	default:
+		dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
+	}
+
+	dev_info(dev, "Prescaler is set to %d.\n",
+		 1 << (config & MAX6650_CFG_PRESCALER_MASK));
+
+	/*
+	 * If mode is set to "full off", we change it to "open loop" and
+	 * set DAC to 255, which has the same effect. We do this because
+	 * there's no "full off" mode defined in hwmon specifications.
+	 */
+
+	if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
+		dev_dbg(dev, "Change mode to open loop, full off.\n");
+		config = (config & ~MAX6650_CFG_MODE_MASK)
+			 | MAX6650_CFG_MODE_OPEN_LOOP;
+		if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
+			dev_err(dev, "DAC write error, aborting.\n");
+			return err;
+		}
+	}
+
+	if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
+		dev_err(dev, "Config write error, aborting.\n");
+		return err;
+	}
+
+	data->config = config;
+	data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+
+	return 0;
+}
+
+static int max6650_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct max6650_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+	data->nr_fans = id->driver_data;
+
+	/*
+	 * Initialize the max6650 chip
+	 */
+	err = max6650_init_client(data, client);
+	if (err)
+		return err;
+
+	data->groups[0] = &max6650_group;
+	/* 3 additional fan inputs for the MAX6651 */
+	if (data->nr_fans == 4)
+		data->groups[1] = &max6651_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   client->name, data,
+							   data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max6650_id[] = {
+	{ "max6650", 1 },
+	{ "max6651", 4 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max6650_id);
+
+static struct i2c_driver max6650_driver = {
+	.driver = {
+		.name	= "max6650",
+	},
+	.probe		= max6650_probe,
+	.id_table	= max6650_id,
+};
+
+module_i2c_driver(max6650_driver);
+
+MODULE_AUTHOR("Hans J. Koch");
+MODULE_DESCRIPTION("MAX6650 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
new file mode 100644
index 0000000..f03a717
--- /dev/null
+++ b/drivers/hwmon/max6697.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * based on max1668.c
+ * Copyright (c) 2011 David George <david.george@ska.ac.za>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+
+#include <linux/platform_data/max6697.h>
+
+enum chips { max6581, max6602, max6622, max6636, max6689, max6693, max6694,
+	     max6697, max6698, max6699 };
+
+/* Report local sensor as temp1 */
+
+static const u8 MAX6697_REG_TEMP[] = {
+			0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08 };
+static const u8 MAX6697_REG_TEMP_EXT[] = {
+			0x57, 0x09, 0x52, 0x53, 0x54, 0x55, 0x56, 0 };
+static const u8 MAX6697_REG_MAX[] = {
+			0x17, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18 };
+static const u8 MAX6697_REG_CRIT[] = {
+			0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 };
+
+/*
+ * Map device tree / platform data register bit map to chip bit map.
+ * Applies to alert register and over-temperature register.
+ */
+#define MAX6697_MAP_BITS(reg)	((((reg) & 0x7e) >> 1) | \
+				 (((reg) & 0x01) << 6) | ((reg) & 0x80))
+
+#define MAX6697_REG_STAT(n)		(0x44 + (n))
+
+#define MAX6697_REG_CONFIG		0x41
+#define MAX6581_CONF_EXTENDED		(1 << 1)
+#define MAX6693_CONF_BETA		(1 << 2)
+#define MAX6697_CONF_RESISTANCE		(1 << 3)
+#define MAX6697_CONF_TIMEOUT		(1 << 5)
+#define MAX6697_REG_ALERT_MASK		0x42
+#define MAX6697_REG_OVERT_MASK		0x43
+
+#define MAX6581_REG_RESISTANCE		0x4a
+#define MAX6581_REG_IDEALITY		0x4b
+#define MAX6581_REG_IDEALITY_SELECT	0x4c
+#define MAX6581_REG_OFFSET		0x4d
+#define MAX6581_REG_OFFSET_SELECT	0x4e
+
+#define MAX6697_CONV_TIME		156	/* ms per channel, worst case */
+
+struct max6697_chip_data {
+	int channels;
+	u32 have_ext;
+	u32 have_crit;
+	u32 have_fault;
+	u8 valid_conf;
+	const u8 *alarm_map;
+};
+
+struct max6697_data {
+	struct i2c_client *client;
+
+	enum chips type;
+	const struct max6697_chip_data *chip;
+
+	int update_interval;	/* in milli-seconds */
+	int temp_offset;	/* in degrees C */
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+	bool valid;		/* true if following fields are valid */
+
+	/* 1x local and up to 7x remote */
+	u8 temp[8][4];		/* [nr][0]=temp [1]=ext [2]=max [3]=crit */
+#define MAX6697_TEMP_INPUT	0
+#define MAX6697_TEMP_EXT	1
+#define MAX6697_TEMP_MAX	2
+#define MAX6697_TEMP_CRIT	3
+	u32 alarms;
+};
+
+/* Diode fault status bits on MAX6581 are right shifted by one bit */
+static const u8 max6581_alarm_map[] = {
+	 0, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23 };
+
+static const struct max6697_chip_data max6697_chip_data[] = {
+	[max6581] = {
+		.channels = 8,
+		.have_crit = 0xff,
+		.have_ext = 0x7f,
+		.have_fault = 0xfe,
+		.valid_conf = MAX6581_CONF_EXTENDED | MAX6697_CONF_TIMEOUT,
+		.alarm_map = max6581_alarm_map,
+	},
+	[max6602] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6622] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6636] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6689] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6693] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+		  MAX6697_CONF_TIMEOUT,
+	},
+	[max6694] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+		  MAX6697_CONF_TIMEOUT,
+	},
+	[max6697] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6698] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x0e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6699] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+};
+
+static struct max6697_data *max6697_update_device(struct device *dev)
+{
+	struct max6697_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct max6697_data *ret = data;
+	int val;
+	int i;
+	u32 alarms;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->valid &&
+	    !time_after(jiffies, data->last_updated
+			+ msecs_to_jiffies(data->update_interval)))
+		goto abort;
+
+	for (i = 0; i < data->chip->channels; i++) {
+		if (data->chip->have_ext & (1 << i)) {
+			val = i2c_smbus_read_byte_data(client,
+						       MAX6697_REG_TEMP_EXT[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i][MAX6697_TEMP_EXT] = val;
+		}
+
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_TEMP[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp[i][MAX6697_TEMP_INPUT] = val;
+
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_MAX[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp[i][MAX6697_TEMP_MAX] = val;
+
+		if (data->chip->have_crit & (1 << i)) {
+			val = i2c_smbus_read_byte_data(client,
+						       MAX6697_REG_CRIT[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i][MAX6697_TEMP_CRIT] = val;
+		}
+	}
+
+	alarms = 0;
+	for (i = 0; i < 3; i++) {
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_STAT(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		alarms = (alarms << 8) | val;
+	}
+	data->alarms = alarms;
+	data->last_updated = jiffies;
+	data->valid = true;
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+	int temp;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = (data->temp[index][MAX6697_TEMP_INPUT] - data->temp_offset) << 3;
+	temp |= data->temp[index][MAX6697_TEMP_EXT] >> 5;
+
+	return sprintf(buf, "%d\n", temp * 125);
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+	int temp;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = data->temp[nr][index];
+	temp -= data->temp_offset;
+
+	return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	if (data->chip->alarm_map)
+		index = data->chip->alarm_map[index];
+
+	return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t set_temp(struct device *dev,
+			struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct max6697_data *data = dev_get_drvdata(dev);
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset;
+	temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127);
+	data->temp[nr][index] = temp;
+	ret = i2c_smbus_write_byte_data(data->client,
+					index == 2 ? MAX6697_REG_MAX[nr]
+						   : MAX6697_REG_CRIT[nr],
+					temp);
+	mutex_unlock(&data->update_lock);
+
+	return ret < 0 ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_input, NULL, 6);
+static SENSOR_DEVICE_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    6, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    6, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_input, NULL, 7);
+static SENSOR_DEVICE_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    7, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    7, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp7_max_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp8_max_alarm, S_IRUGO, show_alarm, NULL, 23);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp7_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp8_crit_alarm, S_IRUGO, show_alarm, NULL, 15);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
+
+static DEVICE_ATTR(dummy, 0, NULL, NULL);
+
+static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
+				  int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct max6697_data *data = dev_get_drvdata(dev);
+	const struct max6697_chip_data *chip = data->chip;
+	int channel = index / 6;	/* channel number */
+	int nr = index % 6;		/* attribute index within channel */
+
+	if (channel >= chip->channels)
+		return 0;
+
+	if ((nr == 3 || nr == 4) && !(chip->have_crit & (1 << channel)))
+		return 0;
+	if (nr == 5 && !(chip->have_fault & (1 << channel)))
+		return 0;
+
+	return attr->mode;
+}
+
+/*
+ * max6697_is_visible uses the index into the following array to determine
+ * if attributes should be created or not. Any change in order or content
+ * must be matched in max6697_is_visible.
+ */
+static struct attribute *max6697_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&dev_attr_dummy.attr,
+
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_max.dev_attr.attr,
+	&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_max.dev_attr.attr,
+	&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_fault.dev_attr.attr,
+
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_max.dev_attr.attr,
+	&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_fault.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max6697_group = {
+	.attrs = max6697_attributes, .is_visible = max6697_is_visible,
+};
+__ATTRIBUTE_GROUPS(max6697);
+
+static void max6697_get_config_of(struct device_node *node,
+				  struct max6697_platform_data *pdata)
+{
+	int len;
+	const __be32 *prop;
+
+	pdata->smbus_timeout_disable =
+		of_property_read_bool(node, "smbus-timeout-disable");
+	pdata->extended_range_enable =
+		of_property_read_bool(node, "extended-range-enable");
+	pdata->beta_compensation =
+		of_property_read_bool(node, "beta-compensation-enable");
+
+	prop = of_get_property(node, "alert-mask", &len);
+	if (prop && len == sizeof(u32))
+		pdata->alert_mask = be32_to_cpu(prop[0]);
+	prop = of_get_property(node, "over-temperature-mask", &len);
+	if (prop && len == sizeof(u32))
+		pdata->over_temperature_mask = be32_to_cpu(prop[0]);
+	prop = of_get_property(node, "resistance-cancellation", &len);
+	if (prop) {
+		if (len == sizeof(u32))
+			pdata->resistance_cancellation = be32_to_cpu(prop[0]);
+		else
+			pdata->resistance_cancellation = 0xfe;
+	}
+	prop = of_get_property(node, "transistor-ideality", &len);
+	if (prop && len == 2 * sizeof(u32)) {
+			pdata->ideality_mask = be32_to_cpu(prop[0]);
+			pdata->ideality_value = be32_to_cpu(prop[1]);
+	}
+}
+
+static int max6697_init_chip(struct max6697_data *data,
+			     struct i2c_client *client)
+{
+	struct max6697_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct max6697_platform_data p;
+	const struct max6697_chip_data *chip = data->chip;
+	int factor = chip->channels;
+	int ret, reg;
+
+	/*
+	 * Don't touch configuration if neither platform data nor OF
+	 * configuration was specified. If that is the case, use the
+	 * current chip configuration.
+	 */
+	if (!pdata && !client->dev.of_node) {
+		reg = i2c_smbus_read_byte_data(client, MAX6697_REG_CONFIG);
+		if (reg < 0)
+			return reg;
+		if (data->type == max6581) {
+			if (reg & MAX6581_CONF_EXTENDED)
+				data->temp_offset = 64;
+			reg = i2c_smbus_read_byte_data(client,
+						       MAX6581_REG_RESISTANCE);
+			if (reg < 0)
+				return reg;
+			factor += hweight8(reg);
+		} else {
+			if (reg & MAX6697_CONF_RESISTANCE)
+				factor++;
+		}
+		goto done;
+	}
+
+	if (client->dev.of_node) {
+		memset(&p, 0, sizeof(p));
+		max6697_get_config_of(client->dev.of_node, &p);
+		pdata = &p;
+	}
+
+	reg = 0;
+	if (pdata->smbus_timeout_disable &&
+	    (chip->valid_conf & MAX6697_CONF_TIMEOUT)) {
+		reg |= MAX6697_CONF_TIMEOUT;
+	}
+	if (pdata->extended_range_enable &&
+	    (chip->valid_conf & MAX6581_CONF_EXTENDED)) {
+		reg |= MAX6581_CONF_EXTENDED;
+		data->temp_offset = 64;
+	}
+	if (pdata->resistance_cancellation &&
+	    (chip->valid_conf & MAX6697_CONF_RESISTANCE)) {
+		reg |= MAX6697_CONF_RESISTANCE;
+		factor++;
+	}
+	if (pdata->beta_compensation &&
+	    (chip->valid_conf & MAX6693_CONF_BETA)) {
+		reg |= MAX6693_CONF_BETA;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_CONFIG, reg);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK,
+					MAX6697_MAP_BITS(pdata->alert_mask));
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK,
+				MAX6697_MAP_BITS(pdata->over_temperature_mask));
+	if (ret < 0)
+		return ret;
+
+	if (data->type == max6581) {
+		factor += hweight8(pdata->resistance_cancellation >> 1);
+		ret = i2c_smbus_write_byte_data(client, MAX6581_REG_RESISTANCE,
+					pdata->resistance_cancellation >> 1);
+		if (ret < 0)
+			return ret;
+		ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
+						pdata->ideality_value);
+		if (ret < 0)
+			return ret;
+		ret = i2c_smbus_write_byte_data(client,
+						MAX6581_REG_IDEALITY_SELECT,
+						pdata->ideality_mask >> 1);
+		if (ret < 0)
+			return ret;
+	}
+done:
+	data->update_interval = factor * MAX6697_CONV_TIME;
+	return 0;
+}
+
+static int max6697_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct max6697_data *data;
+	struct device *hwmon_dev;
+	int err;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct max6697_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->type = id->driver_data;
+	data->chip = &max6697_chip_data[data->type];
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	err = max6697_init_chip(data, client);
+	if (err)
+		return err;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   max6697_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max6697_id[] = {
+	{ "max6581", max6581 },
+	{ "max6602", max6602 },
+	{ "max6622", max6622 },
+	{ "max6636", max6636 },
+	{ "max6689", max6689 },
+	{ "max6693", max6693 },
+	{ "max6694", max6694 },
+	{ "max6697", max6697 },
+	{ "max6698", max6698 },
+	{ "max6699", max6699 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max6697_id);
+
+static struct i2c_driver max6697_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "max6697",
+	},
+	.probe = max6697_probe,
+	.id_table = max6697_id,
+};
+
+module_i2c_driver(max6697_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("MAX6697 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
new file mode 100644
index 0000000..0c02f40
--- /dev/null
+++ b/drivers/hwmon/mc13783-adc.c
@@ -0,0 +1,279 @@
+/*
+ * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
+ *
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/mfd/mc13xxx.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#define DRIVER_NAME	"mc13783-adc"
+
+/* platform device id driver data */
+#define MC13783_ADC_16CHANS	1
+#define MC13783_ADC_BPDIV2	2
+
+struct mc13783_adc_priv {
+	struct mc13xxx *mc13xxx;
+	struct device *hwmon_dev;
+	char name[PLATFORM_NAME_SIZE];
+};
+
+static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", priv->name);
+}
+
+static int mc13783_adc_read(struct device *dev,
+		struct device_attribute *devattr, unsigned int *val)
+{
+	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	unsigned int channel = attr->index;
+	unsigned int sample[4];
+	int ret;
+
+	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
+			MC13XXX_ADC_MODE_MULT_CHAN,
+			channel, 0, 0, sample);
+	if (ret)
+		return ret;
+
+	channel &= 0x7;
+
+	*val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
+
+	return 0;
+}
+
+static ssize_t mc13783_adc_read_bp(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	unsigned val;
+	struct platform_device *pdev = to_platform_device(dev);
+	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
+	int ret = mc13783_adc_read(dev, devattr, &val);
+
+	if (ret)
+		return ret;
+
+	if (driver_data & MC13783_ADC_BPDIV2)
+		val = DIV_ROUND_CLOSEST(val * 9, 2);
+	else
+		/*
+		 * BP (channel 2) reports with offset 2.4V to the actual value
+		 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
+		 */
+		val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t mc13783_adc_read_gp(struct device *dev,
+		struct device_attribute *devattr, char *buf)
+{
+	unsigned val;
+	int ret = mc13783_adc_read(dev, devattr, &val);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * input range is [0, 2.3V], val has 10 bits, so each bit
+	 * is worth 9/4 mV.
+	 */
+	val = DIV_ROUND_CLOSEST(val * 9, 4);
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
+
+static struct attribute *mc13783_attr_base[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group mc13783_group_base = {
+	.attrs = mc13783_attr_base,
+};
+
+/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
+static struct attribute *mc13783_attr_16chans[] = {
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group mc13783_group_16chans = {
+	.attrs = mc13783_attr_16chans,
+};
+
+/* last four channels may be occupied by the touchscreen */
+static struct attribute *mc13783_attr_ts[] = {
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+	&sensor_dev_attr_in14_input.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group mc13783_group_ts = {
+	.attrs = mc13783_attr_ts,
+};
+
+static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
+{
+	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+	unsigned flags = mc13xxx_get_flags(priv->mc13xxx);
+
+	return flags & MC13XXX_USE_TOUCHSCREEN;
+}
+
+static int __init mc13783_adc_probe(struct platform_device *pdev)
+{
+	struct mc13783_adc_priv *priv;
+	int ret;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	char *dash;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+	snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
+	dash = strchr(priv->name, '-');
+	if (dash)
+		*dash = '\0';
+
+	platform_set_drvdata(pdev, priv);
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
+	if (ret)
+		return ret;
+
+	if (id->driver_data & MC13783_ADC_16CHANS) {
+		ret = sysfs_create_group(&pdev->dev.kobj,
+				&mc13783_group_16chans);
+		if (ret)
+			goto out_err_create_16chans;
+	}
+
+	if (!mc13783_adc_use_touchscreen(pdev)) {
+		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
+		if (ret)
+			goto out_err_create_ts;
+	}
+
+	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(priv->hwmon_dev)) {
+		ret = PTR_ERR(priv->hwmon_dev);
+		dev_err(&pdev->dev,
+				"hwmon_device_register failed with %d.\n", ret);
+		goto out_err_register;
+	}
+
+	return 0;
+
+out_err_register:
+
+	if (!mc13783_adc_use_touchscreen(pdev))
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
+out_err_create_ts:
+
+	if (id->driver_data & MC13783_ADC_16CHANS)
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+out_err_create_16chans:
+
+	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
+	return ret;
+}
+
+static int mc13783_adc_remove(struct platform_device *pdev)
+{
+	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
+
+	hwmon_device_unregister(priv->hwmon_dev);
+
+	if (!mc13783_adc_use_touchscreen(pdev))
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
+
+	if (driver_data & MC13783_ADC_16CHANS)
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+
+	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
+
+	return 0;
+}
+
+static const struct platform_device_id mc13783_adc_idtable[] = {
+	{
+		.name = "mc13783-adc",
+		.driver_data = MC13783_ADC_16CHANS,
+	}, {
+		.name = "mc13892-adc",
+		.driver_data = MC13783_ADC_BPDIV2,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
+
+static struct platform_driver mc13783_adc_driver = {
+	.remove		= mc13783_adc_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+	.id_table	= mc13783_adc_idtable,
+};
+
+module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
+
+MODULE_DESCRIPTION("MC13783 ADC driver");
+MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
new file mode 100644
index 0000000..972444a
--- /dev/null
+++ b/drivers/hwmon/mcp3021.c
@@ -0,0 +1,189 @@
+/*
+ * mcp3021.c - driver for Microchip MCP3021 and MCP3221
+ *
+ * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
+ * Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
+ *
+ * This driver export the value of analog input voltage to sysfs, the
+ * voltage unit is mV. Through the sysfs interface, lm-sensors tool
+ * can also display the input voltage.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+/* Vdd info */
+#define MCP3021_VDD_MAX		5500
+#define MCP3021_VDD_MIN		2700
+#define MCP3021_VDD_REF		3300
+
+/* output format */
+#define MCP3021_SAR_SHIFT	2
+#define MCP3021_SAR_MASK	0x3ff
+#define MCP3021_OUTPUT_RES	10	/* 10-bit resolution */
+
+#define MCP3221_SAR_SHIFT	0
+#define MCP3221_SAR_MASK	0xfff
+#define MCP3221_OUTPUT_RES	12	/* 12-bit resolution */
+
+enum chips {
+	mcp3021,
+	mcp3221
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+struct mcp3021_data {
+	struct device *hwmon_dev;
+	u32 vdd;	/* device power supply */
+	u16 sar_shift;
+	u16 sar_mask;
+	u8 output_res;
+};
+
+static int mcp3021_read16(struct i2c_client *client)
+{
+	struct mcp3021_data *data = i2c_get_clientdata(client);
+	int ret;
+	u16 reg;
+	__be16 buf;
+
+	ret = i2c_master_recv(client, (char *)&buf, 2);
+	if (ret < 0)
+		return ret;
+	if (ret != 2)
+		return -EIO;
+
+	/* The output code of the MCP3021 is transmitted with MSB first. */
+	reg = be16_to_cpu(buf);
+
+	/*
+	 * The ten-bit output code is composed of the lower 4-bit of the
+	 * first byte and the upper 6-bit of the second byte.
+	 */
+	reg = (reg >> data->sar_shift) & data->sar_mask;
+
+	return reg;
+}
+
+static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
+{
+	return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
+}
+
+static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mcp3021_data *data = i2c_get_clientdata(client);
+	int reg, in_input;
+
+	reg = mcp3021_read16(client);
+	if (reg < 0)
+		return reg;
+
+	in_input = volts_from_reg(data, reg);
+
+	return sprintf(buf, "%d\n", in_input);
+}
+
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
+
+static int mcp3021_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	int err;
+	struct mcp3021_data *data = NULL;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+
+	switch (id->driver_data) {
+	case mcp3021:
+		data->sar_shift = MCP3021_SAR_SHIFT;
+		data->sar_mask = MCP3021_SAR_MASK;
+		data->output_res = MCP3021_OUTPUT_RES;
+		break;
+
+	case mcp3221:
+		data->sar_shift = MCP3221_SAR_SHIFT;
+		data->sar_mask = MCP3221_SAR_MASK;
+		data->output_res = MCP3221_OUTPUT_RES;
+		break;
+	}
+
+	if (dev_get_platdata(&client->dev)) {
+		data->vdd = *(u32 *)dev_get_platdata(&client->dev);
+		if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
+			return -EINVAL;
+	} else {
+		data->vdd = MCP3021_VDD_REF;
+	}
+
+	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+	if (err)
+		return err;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+	return err;
+}
+
+static int mcp3021_remove(struct i2c_client *client)
+{
+	struct mcp3021_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+
+	return 0;
+}
+
+static const struct i2c_device_id mcp3021_id[] = {
+	{ "mcp3021", mcp3021 },
+	{ "mcp3221", mcp3221 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcp3021_id);
+
+static struct i2c_driver mcp3021_driver = {
+	.driver = {
+		.name = "mcp3021",
+	},
+	.probe = mcp3021_probe,
+	.remove = mcp3021_remove,
+	.id_table = mcp3021_id,
+};
+
+module_i2c_driver(mcp3021_driver);
+
+MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
+MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/menf21bmc_hwmon.c b/drivers/hwmon/menf21bmc_hwmon.c
new file mode 100644
index 0000000..c29a4c3
--- /dev/null
+++ b/drivers/hwmon/menf21bmc_hwmon.c
@@ -0,0 +1,230 @@
+/*
+ *  MEN 14F021P00 Board Management Controller (BMC) hwmon driver.
+ *
+ *  This is the core hwmon driver of the MEN 14F021P00 BMC.
+ *  The BMC monitors the board voltages which can be access with this
+ *  driver through sysfs.
+ *
+ *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#define DRV_NAME  "menf21bmc_hwmon"
+
+#define BMC_VOLT_COUNT	5
+#define MENF21BMC_V33	0
+#define MENF21BMC_V5	1
+#define MENF21BMC_V12	2
+#define MENF21BMC_V5_SB	3
+#define MENF21BMC_VBAT	4
+
+#define IDX_TO_VOLT_MIN_CMD(idx) (0x40 + idx)
+#define IDX_TO_VOLT_MAX_CMD(idx) (0x50 + idx)
+#define IDX_TO_VOLT_INP_CMD(idx) (0x60 + idx)
+
+struct menf21bmc_hwmon {
+	bool valid;
+	struct i2c_client *i2c_client;
+	unsigned long last_update;
+	int in_val[BMC_VOLT_COUNT];
+	int in_min[BMC_VOLT_COUNT];
+	int in_max[BMC_VOLT_COUNT];
+};
+
+static const char *const input_names[] = {
+	[MENF21BMC_V33]		= "MON_3_3V",
+	[MENF21BMC_V5]		= "MON_5V",
+	[MENF21BMC_V12]		= "MON_12V",
+	[MENF21BMC_V5_SB]	= "5V_STANDBY",
+	[MENF21BMC_VBAT]	= "VBAT"
+};
+
+static struct menf21bmc_hwmon *menf21bmc_hwmon_update(struct device *dev)
+{
+	int i;
+	int val;
+	struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+	struct menf21bmc_hwmon *data_ret = drv_data;
+
+	if (time_after(jiffies, drv_data->last_update + HZ)
+	    || !drv_data->valid) {
+		for (i = 0; i < BMC_VOLT_COUNT; i++) {
+			val = i2c_smbus_read_word_data(drv_data->i2c_client,
+						       IDX_TO_VOLT_INP_CMD(i));
+			if (val < 0) {
+				data_ret = ERR_PTR(val);
+				goto abort;
+			}
+			drv_data->in_val[i] = val;
+		}
+		drv_data->last_update = jiffies;
+		drv_data->valid = true;
+	}
+abort:
+	return data_ret;
+}
+
+static int menf21bmc_hwmon_get_volt_limits(struct menf21bmc_hwmon *drv_data)
+{
+	int i, val;
+
+	for (i = 0; i < BMC_VOLT_COUNT; i++) {
+		val = i2c_smbus_read_word_data(drv_data->i2c_client,
+					       IDX_TO_VOLT_MIN_CMD(i));
+		if (val < 0)
+			return val;
+
+		drv_data->in_min[i] = val;
+
+		val = i2c_smbus_read_word_data(drv_data->i2c_client,
+					       IDX_TO_VOLT_MAX_CMD(i));
+		if (val < 0)
+			return val;
+
+		drv_data->in_max[i] = val;
+	}
+	return 0;
+}
+
+static ssize_t
+show_label(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%s\n", input_names[attr->index]);
+}
+
+static ssize_t
+show_in(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct menf21bmc_hwmon *drv_data = menf21bmc_hwmon_update(dev);
+
+	if (IS_ERR(drv_data))
+		return PTR_ERR(drv_data);
+
+	return sprintf(buf, "%d\n", drv_data->in_val[attr->index]);
+}
+
+static ssize_t
+show_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", drv_data->in_min[attr->index]);
+}
+
+static ssize_t
+show_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", drv_data->in_max[attr->index]);
+}
+
+#define create_voltage_sysfs(idx)			\
+static SENSOR_DEVICE_ATTR(in##idx##_input, S_IRUGO,	\
+			show_in, NULL, idx);		\
+static SENSOR_DEVICE_ATTR(in##idx##_min, S_IRUGO,	\
+			show_min, NULL, idx);		\
+static SENSOR_DEVICE_ATTR(in##idx##_max, S_IRUGO,	\
+			show_max, NULL, idx);		\
+static SENSOR_DEVICE_ATTR(in##idx##_label, S_IRUGO,	\
+			show_label, NULL, idx);
+
+create_voltage_sysfs(0);
+create_voltage_sysfs(1);
+create_voltage_sysfs(2);
+create_voltage_sysfs(3);
+create_voltage_sysfs(4);
+
+static struct attribute *menf21bmc_hwmon_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(menf21bmc_hwmon);
+
+static int menf21bmc_hwmon_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct menf21bmc_hwmon *drv_data;
+	struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
+	struct device *hwmon_dev;
+
+	drv_data = devm_kzalloc(&pdev->dev, sizeof(struct menf21bmc_hwmon),
+				GFP_KERNEL);
+	if (!drv_data)
+		return -ENOMEM;
+
+	drv_data->i2c_client = i2c_client;
+
+	ret = menf21bmc_hwmon_get_volt_limits(drv_data);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to read sensor limits");
+		return ret;
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+						   "menf21bmc", drv_data,
+						   menf21bmc_hwmon_groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(&pdev->dev, "MEN 14F021P00 BMC hwmon device enabled");
+
+	return 0;
+}
+
+static struct platform_driver menf21bmc_hwmon = {
+	.probe		= menf21bmc_hwmon_probe,
+	.driver		= {
+		.name		= DRV_NAME,
+	},
+};
+
+module_platform_driver(menf21bmc_hwmon);
+
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_DESCRIPTION("MEN 14F021P00 BMC hwmon");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:menf21bmc_hwmon");
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
new file mode 100644
index 0000000..37f0170
--- /dev/null
+++ b/drivers/hwmon/nct6683.c
@@ -0,0 +1,1458 @@
+/*
+ * nct6683 - Driver for the hardware monitoring functionality of
+ *	     Nuvoton NCT6683D eSIO
+ *
+ * Copyright (C) 2013  Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from nct6775 driver
+ * Copyright (C) 2012, 2013  Guenter Roeck <linux@roeck-us.net>
+ *
+ * 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.
+ *
+ * Supports the following chips:
+ *
+ * Chip        #vin    #fan    #pwm    #temp  chip ID
+ * nct6683d     21(1)   16      8       32(1) 0xc730
+ *
+ * Notes:
+ *	(1) Total number of vin and temp inputs is 32.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum kinds { nct6683 };
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards");
+
+static const char * const nct6683_device_names[] = {
+	"nct6683",
+};
+
+static const char * const nct6683_chip_names[] = {
+	"NCT6683D",
+};
+
+#define DRVNAME "nct6683"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define NCT6683_LD_ACPI		0x0a
+#define NCT6683_LD_HWM		0x0b
+#define NCT6683_LD_VID		0x0d
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+
+#define SIO_NCT6681_ID		0xb270	/* for later */
+#define SIO_NCT6683_ID		0xc730
+#define SIO_ID_MASK		0xFFF0
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+	outb(reg, ioreg);
+	outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+	outb(reg, ioreg);
+	return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+	outb(SIO_REG_LDSEL, ioreg);
+	outb(ld, ioreg + 1);
+}
+
+static inline int
+superio_enter(int ioreg)
+{
+	/*
+	 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+	 */
+	if (!request_muxed_region(ioreg, 2, DRVNAME))
+		return -EBUSY;
+
+	outb(0x87, ioreg);
+	outb(0x87, ioreg);
+
+	return 0;
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+	outb(0xaa, ioreg);
+	outb(0x02, ioreg);
+	outb(0x02, ioreg + 1);
+	release_region(ioreg, 2);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT	(~7)
+#define IOREGION_OFFSET		4	/* Use EC port 1 */
+#define IOREGION_LENGTH		4
+
+#define EC_PAGE_REG		0
+#define EC_INDEX_REG		1
+#define EC_DATA_REG		2
+#define EC_EVENT_REG		3
+
+/* Common and NCT6683 specific data */
+
+#define NCT6683_NUM_REG_MON		32
+#define NCT6683_NUM_REG_FAN		16
+#define NCT6683_NUM_REG_PWM		8
+
+#define NCT6683_REG_MON(x)		(0x100 + (x) * 2)
+#define NCT6683_REG_FAN_RPM(x)		(0x140 + (x) * 2)
+#define NCT6683_REG_PWM(x)		(0x160 + (x))
+
+#define NCT6683_REG_MON_STS(x)		(0x174 + (x))
+#define NCT6683_REG_IDLE(x)		(0x178 + (x))
+
+#define NCT6683_REG_FAN_STS(x)		(0x17c + (x))
+#define NCT6683_REG_FAN_ERRSTS		0x17e
+#define NCT6683_REG_FAN_INITSTS		0x17f
+
+#define NCT6683_HWM_CFG			0x180
+
+#define NCT6683_REG_MON_CFG(x)		(0x1a0 + (x))
+#define NCT6683_REG_FANIN_CFG(x)	(0x1c0 + (x))
+#define NCT6683_REG_FANOUT_CFG(x)	(0x1d0 + (x))
+
+#define NCT6683_REG_INTEL_TEMP_MAX(x)	(0x901 + (x) * 16)
+#define NCT6683_REG_INTEL_TEMP_CRIT(x)	(0x90d + (x) * 16)
+
+#define NCT6683_REG_TEMP_HYST(x)	(0x330 + (x))		/* 8 bit */
+#define NCT6683_REG_TEMP_MAX(x)		(0x350 + (x))		/* 8 bit */
+#define NCT6683_REG_MON_HIGH(x)		(0x370 + (x) * 2)	/* 8 bit */
+#define NCT6683_REG_MON_LOW(x)		(0x371 + (x) * 2)	/* 8 bit */
+
+#define NCT6683_REG_FAN_MIN(x)		(0x3b8 + (x) * 2)	/* 16 bit */
+
+#define NCT6683_REG_CUSTOMER_ID		0x602
+#define NCT6683_CUSTOMER_ID_INTEL	0x805
+
+#define NCT6683_REG_BUILD_YEAR		0x604
+#define NCT6683_REG_BUILD_MONTH		0x605
+#define NCT6683_REG_BUILD_DAY		0x606
+#define NCT6683_REG_SERIAL		0x607
+#define NCT6683_REG_VERSION_HI		0x608
+#define NCT6683_REG_VERSION_LO		0x609
+
+#define NCT6683_REG_CR_CASEOPEN		0xe8
+#define NCT6683_CR_CASEOPEN_MASK	(1 << 7)
+
+#define NCT6683_REG_CR_BEEP		0xe0
+#define NCT6683_CR_BEEP_MASK		(1 << 6)
+
+static const char *const nct6683_mon_label[] = {
+	NULL,	/* disabled */
+	"Local",
+	"Diode 0 (curr)",
+	"Diode 1 (curr)",
+	"Diode 2 (curr)",
+	"Diode 0 (volt)",
+	"Diode 1 (volt)",
+	"Diode 2 (volt)",
+	"Thermistor 14",
+	"Thermistor 15",
+	"Thermistor 16",
+	"Thermistor 0",
+	"Thermistor 1",
+	"Thermistor 2",
+	"Thermistor 3",
+	"Thermistor 4",
+	"Thermistor 5",		/* 0x10 */
+	"Thermistor 6",
+	"Thermistor 7",
+	"Thermistor 8",
+	"Thermistor 9",
+	"Thermistor 10",
+	"Thermistor 11",
+	"Thermistor 12",
+	"Thermistor 13",
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	"PECI 0.0",		/* 0x20 */
+	"PECI 1.0",
+	"PECI 2.0",
+	"PECI 3.0",
+	"PECI 0.1",
+	"PECI 1.1",
+	"PECI 2.1",
+	"PECI 3.1",
+	"PECI DIMM 0",
+	"PECI DIMM 1",
+	"PECI DIMM 2",
+	"PECI DIMM 3",
+	NULL, NULL, NULL, NULL,
+	"PCH CPU",		/* 0x30 */
+	"PCH CHIP",
+	"PCH CHIP CPU MAX",
+	"PCH MCH",
+	"PCH DIMM 0",
+	"PCH DIMM 1",
+	"PCH DIMM 2",
+	"PCH DIMM 3",
+	"SMBus 0",
+	"SMBus 1",
+	"SMBus 2",
+	"SMBus 3",
+	"SMBus 4",
+	"SMBus 5",
+	"DIMM 0",
+	"DIMM 1",
+	"DIMM 2",		/* 0x40 */
+	"DIMM 3",
+	"AMD TSI Addr 90h",
+	"AMD TSI Addr 92h",
+	"AMD TSI Addr 94h",
+	"AMD TSI Addr 96h",
+	"AMD TSI Addr 98h",
+	"AMD TSI Addr 9ah",
+	"AMD TSI Addr 9ch",
+	"AMD TSI Addr 9dh",
+	NULL, NULL, NULL, NULL, NULL, NULL,
+	"Virtual 0",		/* 0x50 */
+	"Virtual 1",
+	"Virtual 2",
+	"Virtual 3",
+	"Virtual 4",
+	"Virtual 5",
+	"Virtual 6",
+	"Virtual 7",
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	"VCC",			/* 0x60 voltage sensors */
+	"VSB",
+	"AVSB",
+	"VTT",
+	"VBAT",
+	"VREF",
+	"VIN0",
+	"VIN1",
+	"VIN2",
+	"VIN3",
+	"VIN4",
+	"VIN5",
+	"VIN6",
+	"VIN7",
+	"VIN8",
+	"VIN9",
+	"VIN10",
+	"VIN11",
+	"VIN12",
+	"VIN13",
+	"VIN14",
+	"VIN15",
+	"VIN16",
+};
+
+#define NUM_MON_LABELS		ARRAY_SIZE(nct6683_mon_label)
+#define MON_VOLTAGE_START	0x60
+
+/* ------------------------------------------------------- */
+
+struct nct6683_data {
+	int addr;		/* IO base of EC space */
+	int sioreg;		/* SIO register */
+	enum kinds kind;
+	u16 customer_id;
+
+	struct device *hwmon_dev;
+	const struct attribute_group *groups[6];
+
+	int temp_num;			/* number of temperature attributes */
+	u8 temp_index[NCT6683_NUM_REG_MON];
+	u8 temp_src[NCT6683_NUM_REG_MON];
+
+	u8 in_num;			/* number of voltage attributes */
+	u8 in_index[NCT6683_NUM_REG_MON];
+	u8 in_src[NCT6683_NUM_REG_MON];
+
+	struct mutex update_lock;	/* used to protect sensor updates */
+	bool valid;			/* true if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* Voltage attribute values */
+	u8 in[3][NCT6683_NUM_REG_MON];	/* [0]=in, [1]=in_max, [2]=in_min */
+
+	/* Temperature attribute values */
+	s16 temp_in[NCT6683_NUM_REG_MON];
+	s8 temp[4][NCT6683_NUM_REG_MON];/* [0]=min, [1]=max, [2]=hyst,
+					 * [3]=crit
+					 */
+
+	/* Fan attribute values */
+	unsigned int rpm[NCT6683_NUM_REG_FAN];
+	u16 fan_min[NCT6683_NUM_REG_FAN];
+	u8 fanin_cfg[NCT6683_NUM_REG_FAN];
+	u8 fanout_cfg[NCT6683_NUM_REG_FAN];
+	u16 have_fan;			/* some fan inputs can be disabled */
+
+	u8 have_pwm;
+	u8 pwm[NCT6683_NUM_REG_PWM];
+
+#ifdef CONFIG_PM
+	/* Remember extra register values over suspend/resume */
+	u8 hwm_cfg;
+#endif
+};
+
+struct nct6683_sio_data {
+	int sioreg;
+	enum kinds kind;
+};
+
+struct sensor_device_template {
+	struct device_attribute dev_attr;
+	union {
+		struct {
+			u8 nr;
+			u8 index;
+		} s;
+		int index;
+	} u;
+	bool s2;	/* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+	union {
+		struct sensor_device_attribute a1;
+		struct sensor_device_attribute_2 a2;
+	} u;
+	char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) {	\
+	.attr = {.name = _template, .mode = _mode },		\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index)	\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.index = _index,						\
+	  .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)				\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.s.index = _index,						\
+	  .u.s.nr = _nr,						\
+	  .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index)	\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store,	\
+				 _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store,	\
+			  _nr, _index)					\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)
+
+struct sensor_template_group {
+	struct sensor_device_template **templates;
+	umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+	int base;
+};
+
+static struct attribute_group *
+nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+			  int repeat)
+{
+	struct sensor_device_attribute_2 *a2;
+	struct sensor_device_attribute *a;
+	struct sensor_device_template **t;
+	struct sensor_device_attr_u *su;
+	struct attribute_group *group;
+	struct attribute **attrs;
+	int i, j, count;
+
+	if (repeat <= 0)
+		return ERR_PTR(-EINVAL);
+
+	t = tg->templates;
+	for (count = 0; *t; t++, count++)
+		;
+
+	if (count == 0)
+		return ERR_PTR(-EINVAL);
+
+	group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+	if (group == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+			     GFP_KERNEL);
+	if (attrs == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+			  GFP_KERNEL);
+	if (su == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	group->attrs = attrs;
+	group->is_visible = tg->is_visible;
+
+	for (i = 0; i < repeat; i++) {
+		t = tg->templates;
+		for (j = 0; *t != NULL; j++) {
+			snprintf(su->name, sizeof(su->name),
+				 (*t)->dev_attr.attr.name, tg->base + i);
+			if ((*t)->s2) {
+				a2 = &su->u.a2;
+				sysfs_attr_init(&a2->dev_attr.attr);
+				a2->dev_attr.attr.name = su->name;
+				a2->nr = (*t)->u.s.nr + i;
+				a2->index = (*t)->u.s.index;
+				a2->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a2->dev_attr.show = (*t)->dev_attr.show;
+				a2->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a2->dev_attr.attr;
+			} else {
+				a = &su->u.a1;
+				sysfs_attr_init(&a->dev_attr.attr);
+				a->dev_attr.attr.name = su->name;
+				a->index = (*t)->u.index + i;
+				a->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a->dev_attr.show = (*t)->dev_attr.show;
+				a->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a->dev_attr.attr;
+			}
+			attrs++;
+			su++;
+			t++;
+		}
+	}
+
+	return group;
+}
+
+/* LSB is 16 mV, except for the following sources, where it is 32 mV */
+#define MON_SRC_VCC	0x60
+#define MON_SRC_VSB	0x61
+#define MON_SRC_AVSB	0x62
+#define MON_SRC_VBAT	0x64
+
+static inline long in_from_reg(u16 reg, u8 src)
+{
+	int scale = 16;
+
+	if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
+	    src == MON_SRC_VBAT)
+		scale <<= 1;
+	return reg * scale;
+}
+
+static inline u16 in_to_reg(u32 val, u8 src)
+{
+	int scale = 16;
+
+	if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
+	    src == MON_SRC_VBAT)
+		scale <<= 1;
+
+	return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127);
+}
+
+static u16 nct6683_read(struct nct6683_data *data, u16 reg)
+{
+	int res;
+
+	outb_p(0xff, data->addr + EC_PAGE_REG);		/* unlock */
+	outb_p(reg >> 8, data->addr + EC_PAGE_REG);
+	outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
+	res = inb_p(data->addr + EC_DATA_REG);
+	return res;
+}
+
+static u16 nct6683_read16(struct nct6683_data *data, u16 reg)
+{
+	return (nct6683_read(data, reg) << 8) | nct6683_read(data, reg + 1);
+}
+
+static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value)
+{
+	outb_p(0xff, data->addr + EC_PAGE_REG);		/* unlock */
+	outb_p(reg >> 8, data->addr + EC_PAGE_REG);
+	outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
+	outb_p(value & 0xff, data->addr + EC_DATA_REG);
+}
+
+static int get_in_reg(struct nct6683_data *data, int nr, int index)
+{
+	int ch = data->in_index[index];
+	int reg = -EINVAL;
+
+	switch (nr) {
+	case 0:
+		reg = NCT6683_REG_MON(ch);
+		break;
+	case 1:
+		if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
+			reg = NCT6683_REG_MON_LOW(ch);
+		break;
+	case 2:
+		if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
+			reg = NCT6683_REG_MON_HIGH(ch);
+		break;
+	default:
+		break;
+	}
+	return reg;
+}
+
+static int get_temp_reg(struct nct6683_data *data, int nr, int index)
+{
+	int ch = data->temp_index[index];
+	int reg = -EINVAL;
+
+	switch (data->customer_id) {
+	case NCT6683_CUSTOMER_ID_INTEL:
+		switch (nr) {
+		default:
+		case 1:	/* max */
+			reg = NCT6683_REG_INTEL_TEMP_MAX(ch);
+			break;
+		case 3:	/* crit */
+			reg = NCT6683_REG_INTEL_TEMP_CRIT(ch);
+			break;
+		}
+		break;
+	default:
+		switch (nr) {
+		default:
+		case 0:	/* min */
+			reg = NCT6683_REG_MON_LOW(ch);
+			break;
+		case 1:	/* max */
+			reg = NCT6683_REG_TEMP_MAX(ch);
+			break;
+		case 2:	/* hyst */
+			reg = NCT6683_REG_TEMP_HYST(ch);
+			break;
+		case 3:	/* crit */
+			reg = NCT6683_REG_MON_HIGH(ch);
+			break;
+		}
+		break;
+	}
+	return reg;
+}
+
+static void nct6683_update_pwm(struct device *dev)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
+		if (!(data->have_pwm & (1 << i)))
+			continue;
+		data->pwm[i] = nct6683_read(data, NCT6683_REG_PWM(i));
+	}
+}
+
+static struct nct6683_data *nct6683_update_device(struct device *dev)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int i, j;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		/* Measured voltages and limits */
+		for (i = 0; i < data->in_num; i++) {
+			for (j = 0; j < 3; j++) {
+				int reg = get_in_reg(data, j, i);
+
+				if (reg >= 0)
+					data->in[j][i] =
+						nct6683_read(data, reg);
+			}
+		}
+
+		/* Measured temperatures and limits */
+		for (i = 0; i < data->temp_num; i++) {
+			u8 ch = data->temp_index[i];
+
+			data->temp_in[i] = nct6683_read16(data,
+							  NCT6683_REG_MON(ch));
+			for (j = 0; j < 4; j++) {
+				int reg = get_temp_reg(data, j, i);
+
+				if (reg >= 0)
+					data->temp[j][i] =
+						nct6683_read(data, reg);
+			}
+		}
+
+		/* Measured fan speeds and limits */
+		for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
+			if (!(data->have_fan & (1 << i)))
+				continue;
+
+			data->rpm[i] = nct6683_read16(data,
+						NCT6683_REG_FAN_RPM(i));
+			data->fan_min[i] = nct6683_read16(data,
+						NCT6683_REG_FAN_MIN(i));
+		}
+
+		nct6683_update_pwm(dev);
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+static ssize_t
+show_in_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%s\n", nct6683_mon_label[data->in_src[nr]]);
+}
+
+static ssize_t
+show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int index = sattr->index;
+	int nr = sattr->nr;
+
+	return sprintf(buf, "%ld\n",
+		       in_from_reg(data->in[index][nr], data->in_index[index]));
+}
+
+static umode_t nct6683_in_is_visible(struct kobject *kobj,
+				     struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int nr = index % 4;	/* attribute */
+
+	/*
+	 * Voltage limits exist for Intel boards,
+	 * but register location and encoding is unknown
+	 */
+	if ((nr == 2 || nr == 3) &&
+	    data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE(in_label, "in%d_label", S_IRUGO, show_in_label, NULL, 0);
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IRUGO, show_in_reg, NULL, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IRUGO, show_in_reg, NULL, 0, 2);
+
+static struct sensor_device_template *nct6683_attributes_in_template[] = {
+	&sensor_dev_template_in_label,
+	&sensor_dev_template_in_input,
+	&sensor_dev_template_in_min,
+	&sensor_dev_template_in_max,
+	NULL
+};
+
+static struct sensor_template_group nct6683_in_template_group = {
+	.templates = nct6683_attributes_in_template,
+	.is_visible = nct6683_in_is_visible,
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->rpm[sattr->index]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6683_data *data = nct6683_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%d\n", data->fan_min[nr]);
+}
+
+static ssize_t
+show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		       ((data->fanin_cfg[sattr->index] >> 5) & 0x03) + 1);
+}
+
+static umode_t nct6683_fan_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int fan = index / 3;	/* fan index */
+	int nr = index % 3;	/* attribute index */
+
+	if (!(data->have_fan & (1 << fan)))
+		return 0;
+
+	/*
+	 * Intel may have minimum fan speed limits,
+	 * but register location and encoding are unknown.
+	 */
+	if (nr == 2 && data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IRUGO, show_fan_pulses, NULL, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IRUGO, show_fan_min, NULL, 0);
+
+/*
+ * nct6683_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6683_attributes_fan_template[] = {
+	&sensor_dev_template_fan_input,
+	&sensor_dev_template_fan_pulses,
+	&sensor_dev_template_fan_min,
+	NULL
+};
+
+static struct sensor_template_group nct6683_fan_template_group = {
+	.templates = nct6683_attributes_fan_template,
+	.is_visible = nct6683_fan_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%s\n", nct6683_mon_label[data->temp_src[nr]]);
+}
+
+static ssize_t
+show_temp8(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int index = sattr->index;
+	int nr = sattr->nr;
+
+	return sprintf(buf, "%d\n", data->temp[index][nr] * 1000);
+}
+
+static ssize_t
+show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int nr = sattr->index;
+	int temp = data->temp[1][nr] - data->temp[2][nr];
+
+	return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t
+show_temp16(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6683_data *data = nct6683_update_device(dev);
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n", (data->temp_in[index] / 128) * 500);
+}
+
+/*
+ * Temperature sensor type is determined by temperature source
+ * and can not be modified.
+ * 0x02..0x07: Thermal diode
+ * 0x08..0x18: Thermistor
+ * 0x20..0x2b: Intel PECI
+ * 0x42..0x49: AMD TSI
+ * Others are unspecified (not visible)
+ */
+
+static int get_temp_type(u8 src)
+{
+	if (src >= 0x02 && src <= 0x07)
+		return 3;	/* thermal diode */
+	else if (src >= 0x08 && src <= 0x18)
+		return 4;	/* thermistor */
+	else if (src >= 0x20 && src <= 0x2b)
+		return 6;	/* PECI */
+	else if (src >= 0x42 && src <= 0x49)
+		return 5;
+
+	return 0;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6683_data *data = nct6683_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	return sprintf(buf, "%d\n", get_temp_type(data->temp_src[nr]));
+}
+
+static umode_t nct6683_temp_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int temp = index / 7;	/* temp index */
+	int nr = index % 7;	/* attribute index */
+
+	/*
+	 * Intel does not have low temperature limits or temperature hysteresis
+	 * registers, or at least register location and encoding is unknown.
+	 */
+	if ((nr == 2 || nr == 4) &&
+	    data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+		return 0;
+
+	if (nr == 6 && get_temp_type(data->temp_src[temp]) == 0)
+		return 0;				/* type */
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE(temp_input, "temp%d_input", S_IRUGO, show_temp16, NULL, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_min, "temp%d_min", S_IRUGO, show_temp8, NULL, 0, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO, show_temp8, NULL, 0, 1);
+SENSOR_TEMPLATE(temp_max_hyst, "temp%d_max_hyst", S_IRUGO, show_temp_hyst, NULL,
+		0);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO, show_temp8, NULL, 0, 3);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO, show_temp_type, NULL, 0);
+
+/*
+ * nct6683_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6683_attributes_temp_template[] = {
+	&sensor_dev_template_temp_input,
+	&sensor_dev_template_temp_label,
+	&sensor_dev_template_temp_min,		/* 2 */
+	&sensor_dev_template_temp_max,		/* 3 */
+	&sensor_dev_template_temp_max_hyst,	/* 4 */
+	&sensor_dev_template_temp_crit,		/* 5 */
+	&sensor_dev_template_temp_type,		/* 6 */
+	NULL
+};
+
+static struct sensor_template_group nct6683_temp_template_group = {
+	.templates = nct6683_attributes_temp_template,
+	.is_visible = nct6683_temp_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6683_data *data = nct6683_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n", data->pwm[index]);
+}
+
+SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0);
+
+static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int pwm = index;	/* pwm index */
+
+	if (!(data->have_pwm & (1 << pwm)))
+		return 0;
+
+	return attr->mode;
+}
+
+static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
+	&sensor_dev_template_pwm,
+	NULL
+};
+
+static struct sensor_template_group nct6683_pwm_template_group = {
+	.templates = nct6683_attributes_pwm_template,
+	.is_visible = nct6683_pwm_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_global_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int ret;
+	u8 reg;
+
+	mutex_lock(&data->update_lock);
+
+	ret = superio_enter(data->sioreg);
+	if (ret)
+		goto error;
+	superio_select(data->sioreg, NCT6683_LD_HWM);
+	reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
+	superio_exit(data->sioreg);
+
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n", !!(reg & NCT6683_CR_BEEP_MASK));
+
+error:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t
+store_global_beep(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u8 reg;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	ret = superio_enter(data->sioreg);
+	if (ret) {
+		count = ret;
+		goto error;
+	}
+
+	superio_select(data->sioreg, NCT6683_LD_HWM);
+	reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
+	if (val)
+		reg |= NCT6683_CR_BEEP_MASK;
+	else
+		reg &= ~NCT6683_CR_BEEP_MASK;
+	superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg);
+	superio_exit(data->sioreg);
+error:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* Case open detection */
+
+static ssize_t
+show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	int ret;
+	u8 reg;
+
+	mutex_lock(&data->update_lock);
+
+	ret = superio_enter(data->sioreg);
+	if (ret)
+		goto error;
+	superio_select(data->sioreg, NCT6683_LD_ACPI);
+	reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
+	superio_exit(data->sioreg);
+
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%u\n", !(reg & NCT6683_CR_CASEOPEN_MASK));
+
+error:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u8 reg;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val) || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	/*
+	 * Use CR registers to clear caseopen status.
+	 * Caseopen is activ low, clear by writing 1 into the register.
+	 */
+
+	ret = superio_enter(data->sioreg);
+	if (ret) {
+		count = ret;
+		goto error;
+	}
+
+	superio_select(data->sioreg, NCT6683_LD_ACPI);
+	reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
+	reg |= NCT6683_CR_CASEOPEN_MASK;
+	superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
+	reg &= ~NCT6683_CR_CASEOPEN_MASK;
+	superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
+	superio_exit(data->sioreg);
+
+	data->valid = false;	/* Force cache refresh */
+error:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+		   clear_caseopen);
+static DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_global_beep,
+		   store_global_beep);
+
+static struct attribute *nct6683_attributes_other[] = {
+	&dev_attr_intrusion0_alarm.attr,
+	&dev_attr_beep_enable.attr,
+	NULL
+};
+
+static const struct attribute_group nct6683_group_other = {
+	.attrs = nct6683_attributes_other,
+};
+
+/* Get the monitoring functions started */
+static inline void nct6683_init_device(struct nct6683_data *data)
+{
+	u8 tmp;
+
+	/* Start hardware monitoring if needed */
+	tmp = nct6683_read(data, NCT6683_HWM_CFG);
+	if (!(tmp & 0x80))
+		nct6683_write(data, NCT6683_HWM_CFG, tmp | 0x80);
+}
+
+/*
+ * There are a total of 24 fan inputs. Each can be configured as input
+ * or as output. A maximum of 16 inputs and 8 outputs is configurable.
+ */
+static void
+nct6683_setup_fans(struct nct6683_data *data)
+{
+	int i;
+	u8 reg;
+
+	for (i = 0; i < NCT6683_NUM_REG_FAN; i++) {
+		reg = nct6683_read(data, NCT6683_REG_FANIN_CFG(i));
+		if (reg & 0x80)
+			data->have_fan |= 1 << i;
+		data->fanin_cfg[i] = reg;
+	}
+	for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
+		reg = nct6683_read(data, NCT6683_REG_FANOUT_CFG(i));
+		if (reg & 0x80)
+			data->have_pwm |= 1 << i;
+		data->fanout_cfg[i] = reg;
+	}
+}
+
+/*
+ * Translation from monitoring register to temperature and voltage attributes
+ * ==========================================================================
+ *
+ * There are a total of 32 monitoring registers. Each can be assigned to either
+ * a temperature or voltage monitoring source.
+ * NCT6683_REG_MON_CFG(x) defines assignment for each monitoring source.
+ *
+ * Temperature and voltage attribute mapping is determined by walking through
+ * the NCT6683_REG_MON_CFG registers. If the assigned source is
+ * a temperature, temp_index[n] is set to the monitor register index, and
+ * temp_src[n] is set to the temperature source. If the assigned source is
+ * a voltage, the respective values are stored in in_index[] and in_src[],
+ * respectively.
+ */
+
+static void nct6683_setup_sensors(struct nct6683_data *data)
+{
+	u8 reg;
+	int i;
+
+	data->temp_num = 0;
+	data->in_num = 0;
+	for (i = 0; i < NCT6683_NUM_REG_MON; i++) {
+		reg = nct6683_read(data, NCT6683_REG_MON_CFG(i)) & 0x7f;
+		/* Ignore invalid assignments */
+		if (reg >= NUM_MON_LABELS)
+			continue;
+		/* Skip if disabled or reserved */
+		if (nct6683_mon_label[reg] == NULL)
+			continue;
+		if (reg < MON_VOLTAGE_START) {
+			data->temp_index[data->temp_num] = i;
+			data->temp_src[data->temp_num] = reg;
+			data->temp_num++;
+		} else {
+			data->in_index[data->in_num] = i;
+			data->in_src[data->in_num] = reg;
+			data->in_num++;
+		}
+	}
+}
+
+static int nct6683_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct nct6683_sio_data *sio_data = dev->platform_data;
+	struct attribute_group *group;
+	struct nct6683_data *data;
+	struct device *hwmon_dev;
+	struct resource *res;
+	int groups = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
+		return -EBUSY;
+
+	data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->kind = sio_data->kind;
+	data->sioreg = sio_data->sioreg;
+	data->addr = res->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
+
+	nct6683_init_device(data);
+	nct6683_setup_fans(data);
+	nct6683_setup_sensors(data);
+
+	/* Register sysfs hooks */
+
+	if (data->have_pwm) {
+		group = nct6683_create_attr_group(dev,
+						  &nct6683_pwm_template_group,
+						  fls(data->have_pwm));
+		if (IS_ERR(group))
+			return PTR_ERR(group);
+		data->groups[groups++] = group;
+	}
+
+	if (data->in_num) {
+		group = nct6683_create_attr_group(dev,
+						  &nct6683_in_template_group,
+						  data->in_num);
+		if (IS_ERR(group))
+			return PTR_ERR(group);
+		data->groups[groups++] = group;
+	}
+
+	if (data->have_fan) {
+		group = nct6683_create_attr_group(dev,
+						  &nct6683_fan_template_group,
+						  fls(data->have_fan));
+		if (IS_ERR(group))
+			return PTR_ERR(group);
+		data->groups[groups++] = group;
+	}
+
+	if (data->temp_num) {
+		group = nct6683_create_attr_group(dev,
+						  &nct6683_temp_template_group,
+						  data->temp_num);
+		if (IS_ERR(group))
+			return PTR_ERR(group);
+		data->groups[groups++] = group;
+	}
+	data->groups[groups++] = &nct6683_group_other;
+
+	dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n",
+		 nct6683_chip_names[data->kind],
+		 nct6683_read(data, NCT6683_REG_VERSION_HI),
+		 nct6683_read(data, NCT6683_REG_VERSION_LO),
+		 nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+		 nct6683_read(data, NCT6683_REG_BUILD_DAY),
+		 nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+			nct6683_device_names[data->kind], data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+#ifdef CONFIG_PM
+static int nct6683_suspend(struct device *dev)
+{
+	struct nct6683_data *data = nct6683_update_device(dev);
+
+	mutex_lock(&data->update_lock);
+	data->hwm_cfg = nct6683_read(data, NCT6683_HWM_CFG);
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static int nct6683_resume(struct device *dev)
+{
+	struct nct6683_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->update_lock);
+
+	nct6683_write(data, NCT6683_HWM_CFG, data->hwm_cfg);
+
+	/* Force re-reading all values */
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops nct6683_dev_pm_ops = {
+	.suspend = nct6683_suspend,
+	.resume = nct6683_resume,
+	.freeze = nct6683_suspend,
+	.restore = nct6683_resume,
+};
+
+#define NCT6683_DEV_PM_OPS	(&nct6683_dev_pm_ops)
+#else
+#define NCT6683_DEV_PM_OPS	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nct6683_driver = {
+	.driver = {
+		.name	= DRVNAME,
+		.pm	= NCT6683_DEV_PM_OPS,
+	},
+	.probe		= nct6683_probe,
+};
+
+static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
+{
+	const char *board_vendor;
+	int addr;
+	u16 val;
+	int err;
+
+	/*
+	 * Only run on Intel boards unless the 'force' module parameter is set
+	 */
+	if (!force) {
+		board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+		if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
+			return -ENODEV;
+	}
+
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
+
+	val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+	       | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+
+	switch (val & SIO_ID_MASK) {
+	case SIO_NCT6683_ID:
+		sio_data->kind = nct6683;
+		break;
+	default:
+		if (val != 0xffff)
+			pr_debug("unsupported chip ID: 0x%04x\n", val);
+		goto fail;
+	}
+
+	/* We have a known chip, find the HWM I/O address */
+	superio_select(sioaddr, NCT6683_LD_HWM);
+	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+	addr = val & IOREGION_ALIGNMENT;
+	if (addr == 0) {
+		pr_err("EC base I/O port unconfigured\n");
+		goto fail;
+	}
+
+	/* Activate logical device if needed */
+	val = superio_inb(sioaddr, SIO_REG_ENABLE);
+	if (!(val & 0x01)) {
+		pr_err("EC is disabled\n");
+		goto fail;
+	}
+
+	superio_exit(sioaddr);
+	pr_info("Found %s or compatible chip at %#x:%#x\n",
+		nct6683_chip_names[sio_data->kind], sioaddr, addr);
+	sio_data->sioreg = sioaddr;
+
+	return addr;
+
+fail:
+	superio_exit(sioaddr);
+	return -ENODEV;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the nct6683 driver. But since we use platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev[2];
+
+static int __init sensors_nct6683_init(void)
+{
+	struct nct6683_sio_data sio_data;
+	int sioaddr[2] = { 0x2e, 0x4e };
+	struct resource res;
+	bool found = false;
+	int address;
+	int i, err;
+
+	err = platform_driver_register(&nct6683_driver);
+	if (err)
+		return err;
+
+	/*
+	 * initialize sio_data->kind and sio_data->sioreg.
+	 *
+	 * when Super-I/O functions move to a separate file, the Super-I/O
+	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+	 * nct6683 hardware monitor, and call probe()
+	 */
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		address = nct6683_find(sioaddr[i], &sio_data);
+		if (address <= 0)
+			continue;
+
+		found = true;
+
+		pdev[i] = platform_device_alloc(DRVNAME, address);
+		if (!pdev[i]) {
+			err = -ENOMEM;
+			goto exit_device_unregister;
+		}
+
+		err = platform_device_add_data(pdev[i], &sio_data,
+					       sizeof(struct nct6683_sio_data));
+		if (err)
+			goto exit_device_put;
+
+		memset(&res, 0, sizeof(res));
+		res.name = DRVNAME;
+		res.start = address + IOREGION_OFFSET;
+		res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+		res.flags = IORESOURCE_IO;
+
+		err = acpi_check_resource_conflict(&res);
+		if (err) {
+			platform_device_put(pdev[i]);
+			pdev[i] = NULL;
+			continue;
+		}
+
+		err = platform_device_add_resources(pdev[i], &res, 1);
+		if (err)
+			goto exit_device_put;
+
+		/* platform_device_add calls probe() */
+		err = platform_device_add(pdev[i]);
+		if (err)
+			goto exit_device_put;
+	}
+	if (!found) {
+		err = -ENODEV;
+		goto exit_unregister;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev[i]);
+exit_device_unregister:
+	while (--i >= 0) {
+		if (pdev[i])
+			platform_device_unregister(pdev[i]);
+	}
+exit_unregister:
+	platform_driver_unregister(&nct6683_driver);
+	return err;
+}
+
+static void __exit sensors_nct6683_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		if (pdev[i])
+			platform_device_unregister(pdev[i]);
+	}
+	platform_driver_unregister(&nct6683_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT6683D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6683_init);
+module_exit(sensors_nct6683_exit);
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
new file mode 100644
index 0000000..d7ebdf8
--- /dev/null
+++ b/drivers/hwmon/nct6775.c
@@ -0,0 +1,4401 @@
+/*
+ * nct6775 - Driver for the hardware monitoring functionality of
+ *	       Nuvoton NCT677x Super-I/O chips
+ *
+ * Copyright (C) 2012  Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from w83627ehf driver
+ * Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2006  Yuan Mu (Winbond),
+ *		       Rudolf Marek <r.marek@assembler.cz>
+ *		       David Hubbard <david.c.hubbard@gmail.com>
+ *		       Daniel J Blueman <daniel.blueman@gmail.com>
+ * Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
+ *
+ * Shamelessly ripped from the w83627hf driver
+ * Copyright (C) 2003  Mark Studebaker
+ *
+ * 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.
+ *
+ *
+ * Supports the following chips:
+ *
+ * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+ * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
+ * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
+ * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
+ * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
+ * nct6791d    15      6       6       2+6    0xc800 0xc1    0x5ca3
+ * nct6792d    15      6       6       2+6    0xc910 0xc1    0x5ca3
+ * nct6793d    15      6       6       2+6    0xd120 0xc1    0x5ca3
+ *
+ * #temp lists the number of monitored temperature sources (first value) plus
+ * the number of directly connectable temperature sensors (second value).
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+#include "lm75.h"
+
+#define USE_ALTERNATE
+
+enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
+
+/* used to set data->name = nct6775_device_names[data->sio_kind] */
+static const char * const nct6775_device_names[] = {
+	"nct6106",
+	"nct6775",
+	"nct6776",
+	"nct6779",
+	"nct6791",
+	"nct6792",
+	"nct6793",
+};
+
+static const char * const nct6775_sio_names[] __initconst = {
+	"NCT6106D",
+	"NCT6775F",
+	"NCT6776D/F",
+	"NCT6779D",
+	"NCT6791D",
+	"NCT6792D",
+	"NCT6793D",
+};
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static unsigned short fan_debounce;
+module_param(fan_debounce, ushort, 0);
+MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
+
+#define DRVNAME "nct6775"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define NCT6775_LD_ACPI		0x0a
+#define NCT6775_LD_HWM		0x0b
+#define NCT6775_LD_VID		0x0d
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+
+#define SIO_NCT6106_ID		0xc450
+#define SIO_NCT6775_ID		0xb470
+#define SIO_NCT6776_ID		0xc330
+#define SIO_NCT6779_ID		0xc560
+#define SIO_NCT6791_ID		0xc800
+#define SIO_NCT6792_ID		0xc910
+#define SIO_NCT6793_ID		0xd120
+#define SIO_ID_MASK		0xFFF0
+
+enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+	outb(reg, ioreg);
+	outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+	outb(reg, ioreg);
+	return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+	outb(SIO_REG_LDSEL, ioreg);
+	outb(ld, ioreg + 1);
+}
+
+static inline int
+superio_enter(int ioreg)
+{
+	/*
+	 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+	 */
+	if (!request_muxed_region(ioreg, 2, DRVNAME))
+		return -EBUSY;
+
+	outb(0x87, ioreg);
+	outb(0x87, ioreg);
+
+	return 0;
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+	outb(0xaa, ioreg);
+	outb(0x02, ioreg);
+	outb(0x02, ioreg + 1);
+	release_region(ioreg, 2);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT	(~7)
+#define IOREGION_OFFSET		5
+#define IOREGION_LENGTH		2
+#define ADDR_REG_OFFSET		0
+#define DATA_REG_OFFSET		1
+
+#define NCT6775_REG_BANK	0x4E
+#define NCT6775_REG_CONFIG	0x40
+
+/*
+ * Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58
+ */
+
+#define NUM_TEMP	10	/* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP_FIXED	6	/* Max number of fixed temp attribute sets */
+
+#define NUM_REG_ALARM	7	/* Max number of alarm registers */
+#define NUM_REG_BEEP	5	/* Max number of beep registers */
+
+#define NUM_FAN		6
+
+/* Common and NCT6775 specific data */
+
+/* Voltage min/max registers for nr=7..14 are in bank 5 */
+
+static const u16 NCT6775_REG_IN_MAX[] = {
+	0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
+	0x55c, 0x55e, 0x560, 0x562 };
+static const u16 NCT6775_REG_IN_MIN[] = {
+	0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
+	0x55d, 0x55f, 0x561, 0x563 };
+static const u16 NCT6775_REG_IN[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
+};
+
+#define NCT6775_REG_VBAT		0x5D
+#define NCT6775_REG_DIODE		0x5E
+#define NCT6775_DIODE_MASK		0x02
+
+#define NCT6775_REG_FANDIV1		0x506
+#define NCT6775_REG_FANDIV2		0x507
+
+#define NCT6775_REG_CR_FAN_DEBOUNCE	0xf0
+
+static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
+
+/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
+
+static const s8 NCT6775_ALARM_BITS[] = {
+	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
+	17, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	-1,				/* unused */
+	6, 7, 11, -1, -1,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, -1 };			/* intrusion0, intrusion1 */
+
+#define FAN_ALARM_BASE		16
+#define TEMP_ALARM_BASE		24
+#define INTRUSION_ALARM_BASE	30
+
+static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
+
+/*
+ * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
+ * 30..31 intrusion
+ */
+static const s8 NCT6775_BEEP_BITS[] = {
+	0, 1, 2, 3, 8, 9, 10, 16,	/* in0.. in7 */
+	17, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	21,				/* global beep enable */
+	6, 7, 11, 28, -1,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, -1 };			/* intrusion0, intrusion1 */
+
+#define BEEP_ENABLE_BASE		15
+
+static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
+static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
+
+/* DC or PWM output fan configuration */
+static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
+static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
+
+/* Advanced Fan control, some values are common for all fans */
+
+static const u16 NCT6775_REG_TARGET[] = {
+	0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
+static const u16 NCT6775_REG_FAN_MODE[] = {
+	0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
+static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
+	0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
+static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
+	0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
+	0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
+	0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
+	0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
+static const u16 NCT6775_REG_PWM[] = {
+	0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
+static const u16 NCT6775_REG_PWM_READ[] = {
+	0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
+
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
+static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
+
+static const u16 NCT6775_REG_TEMP[] = {
+	0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
+
+static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
+
+static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+	0, 0x152, 0x252, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+	0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+	0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
+
+static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+	0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
+
+static const u16 NCT6775_REG_TEMP_SEL[] = {
+	0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
+
+static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
+	0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
+	0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
+	0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
+static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
+	0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
+static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
+	0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
+
+static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
+
+static const u16 NCT6775_REG_AUTO_TEMP[] = {
+	0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
+static const u16 NCT6775_REG_AUTO_PWM[] = {
+	0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
+
+#define NCT6775_AUTO_TEMP(data, nr, p)	((data)->REG_AUTO_TEMP[nr] + (p))
+#define NCT6775_AUTO_PWM(data, nr, p)	((data)->REG_AUTO_PWM[nr] + (p))
+
+static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
+
+static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
+	0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
+static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
+	0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
+
+static const char *const nct6775_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMD SB-TSI",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4",
+	"PECI Agent 5",
+	"PECI Agent 6",
+	"PECI Agent 7",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP"
+};
+
+static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
+
+static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
+	= { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
+	    0xa07 };
+
+/* NCT6776 specific data */
+
+/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
+#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
+#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
+
+static const s8 NCT6776_ALARM_BITS[] = {
+	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
+	17, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	-1,				/* unused */
+	6, 7, 11, 10, 23,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, 9 };			/* intrusion0, intrusion1 */
+
+static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const s8 NCT6776_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 6, 7,		/* in0.. in7 */
+	8, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	24,				/* global beep enable */
+	25, 26, 27, 28, 29,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	30, 31 };			/* intrusion0, intrusion1 */
+
+static const u16 NCT6776_REG_TOLERANCE_H[] = {
+	0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
+
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
+
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
+static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
+
+static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
+	0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
+
+static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+	0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
+
+static const char *const nct6776_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP"
+};
+
+static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
+
+static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+/* NCT6779 specific data */
+
+static const u16 NCT6779_REG_IN[] = {
+	0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
+	0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
+
+static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
+	0x459, 0x45A, 0x45B, 0x568 };
+
+static const s8 NCT6779_ALARM_BITS[] = {
+	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
+	17, 24, 25, 26, 27, 28, 29,	/* in8..in14 */
+	-1,				/* unused */
+	6, 7, 11, 10, 23,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, 9 };			/* intrusion0, intrusion1 */
+
+static const s8 NCT6779_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 6, 7,		/* in0.. in7 */
+	8, 9, 10, 11, 12, 13, 14,	/* in8..in14 */
+	24,				/* global beep enable */
+	25, 26, 27, 28, 29,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, -1, -1, -1, -1,		/* temp1..temp6 */
+	30, 31 };			/* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = {
+	0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
+static const u16 NCT6779_REG_FAN_PULSES[] = {
+	0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
+
+static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
+	0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
+#define NCT6779_CRITICAL_PWM_ENABLE_MASK	0x01
+static const u16 NCT6779_REG_CRITICAL_PWM[] = {
+	0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
+
+static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
+static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
+static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+	0x18, 0x152 };
+static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+	0x3a, 0x153 };
+static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+	0x39, 0x155 };
+
+static const u16 NCT6779_REG_TEMP_OFFSET[] = {
+	0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+
+static const char *const nct6779_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN0",
+	"AUXTIN1",
+	"AUXTIN2",
+	"AUXTIN3",
+	"",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP",
+	"",
+	"",
+	"",
+	"",
+	"Virtual_TEMP"
+};
+
+#define NCT6779_NUM_LABELS	(ARRAY_SIZE(nct6779_temp_label) - 5)
+#define NCT6791_NUM_LABELS	ARRAY_SIZE(nct6779_temp_label)
+
+static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
+	= { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
+	    0x408, 0 };
+
+static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+/* NCT6791 specific data */
+
+#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE	0x28
+
+static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
+static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
+static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
+static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
+static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
+static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
+
+static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
+	0x459, 0x45A, 0x45B, 0x568, 0x45D };
+
+static const s8 NCT6791_ALARM_BITS[] = {
+	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
+	17, 24, 25, 26, 27, 28, 29,	/* in8..in14 */
+	-1,				/* unused */
+	6, 7, 11, 10, 23, 33,		/* fan1..fan6 */
+	-1, -1,				/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, 9 };			/* intrusion0, intrusion1 */
+
+/* NCT6792/NCT6793 specific data */
+
+static const u16 NCT6792_REG_TEMP_MON[] = {
+	0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
+static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
+	0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
+
+static const char *const nct6792_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN0",
+	"AUXTIN1",
+	"AUXTIN2",
+	"AUXTIN3",
+	"",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP",
+	"PECI Agent 0 Calibration",
+	"PECI Agent 1 Calibration",
+	"",
+	"",
+	"Virtual_TEMP"
+};
+
+static const char *const nct6793_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN0",
+	"AUXTIN1",
+	"AUXTIN2",
+	"AUXTIN3",
+	"",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"Agent0 Dimm0 ",
+	"Agent0 Dimm1",
+	"Agent1 Dimm0",
+	"Agent1 Dimm1",
+	"BYTE_TEMP0",
+	"BYTE_TEMP1",
+	"PECI Agent 0 Calibration",
+	"PECI Agent 1 Calibration",
+	"",
+	"Virtual_TEMP"
+};
+
+/* NCT6102D/NCT6106D specific data */
+
+#define NCT6106_REG_VBAT	0x318
+#define NCT6106_REG_DIODE	0x319
+#define NCT6106_DIODE_MASK	0x01
+
+static const u16 NCT6106_REG_IN_MAX[] = {
+	0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
+static const u16 NCT6106_REG_IN_MIN[] = {
+	0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
+static const u16 NCT6106_REG_IN[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
+
+static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
+static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
+static const u16 NCT6106_REG_TEMP_HYST[] = {
+	0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
+static const u16 NCT6106_REG_TEMP_OVER[] = {
+	0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
+static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
+	0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
+static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
+	0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
+static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
+static const u16 NCT6106_REG_TEMP_CONFIG[] = {
+	0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
+
+static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
+static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
+static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
+static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
+
+static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
+static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
+static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
+static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
+static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
+static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
+static const u16 NCT6106_REG_TEMP_SOURCE[] = {
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
+static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
+	0x11b, 0x12b, 0x13b };
+
+static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
+#define NCT6106_CRITICAL_PWM_ENABLE_MASK	0x10
+static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
+
+static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
+static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
+static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
+static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
+static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
+static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
+
+static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
+
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+
+static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
+static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
+
+static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
+	0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
+
+static const s8 NCT6106_ALARM_BITS[] = {
+	0, 1, 2, 3, 4, 5, 7, 8,		/* in0.. in7 */
+	9, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	-1,				/* unused */
+	32, 33, 34, -1, -1,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	48, -1				/* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
+	0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
+
+static const s8 NCT6106_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 7, 8,		/* in0.. in7 */
+	9, 10, 11, 12, -1, -1, -1,	/* in8..in14 */
+	32,				/* global beep enable */
+	24, 25, 26, 27, 28,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	34, -1				/* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
+
+static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
+
+static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
+{
+	if (mode == 0 && pwm == 255)
+		return off;
+	return mode + 1;
+}
+
+static int pwm_enable_to_reg(enum pwm_enable mode)
+{
+	if (mode == off)
+		return 0;
+	return mode - 1;
+}
+
+/*
+ * Conversions
+ */
+
+/* 1 is DC mode, output in ms */
+static unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+	return mode ? 400 * reg : 100 * reg;
+}
+
+static u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+	return clamp_val((mode ? (msec + 200) / 400 :
+					(msec + 50) / 100), 1, 255);
+}
+
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
+{
+	if (reg == 0 || reg == 255)
+		return 0;
+	return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+	if ((reg & 0xff1f) == 0xff1f)
+		return 0;
+
+	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+	if (reg == 0)
+		return 0;
+
+	return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+	if (reg == 0 || reg == 0xffff)
+		return 0;
+
+	/*
+	 * Even though the registers are 16 bit wide, the fan divisor
+	 * still applies.
+	 */
+	return 1350000U / (reg << divreg);
+}
+
+static u16 fan_to_reg(u32 fan, unsigned int divreg)
+{
+	if (!fan)
+		return 0;
+
+	return (1350000U / fan) >> divreg;
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+	return 1 << reg;
+}
+
+/*
+ * Some of the voltage inputs have internal scaling, the tables below
+ * contain 8 (the ADC LSB in mV) * scaling factor * 100
+ */
+static const u16 scale_in[15] = {
+	800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
+	800, 800
+};
+
+static inline long in_from_reg(u8 reg, u8 nr)
+{
+	return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
+}
+
+static inline u8 in_to_reg(u32 val, u8 nr)
+{
+	return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
+}
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct nct6775_data {
+	int addr;	/* IO base of hw monitor block */
+	int sioreg;	/* SIO register address */
+	enum kinds kind;
+	const char *name;
+
+	const struct attribute_group *groups[6];
+
+	u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+				    * 3=temp_crit, 4=temp_lcrit
+				    */
+	u8 temp_src[NUM_TEMP];
+	u16 reg_temp_config[NUM_TEMP];
+	const char * const *temp_label;
+	int temp_label_num;
+
+	u16 REG_CONFIG;
+	u16 REG_VBAT;
+	u16 REG_DIODE;
+	u8 DIODE_MASK;
+
+	const s8 *ALARM_BITS;
+	const s8 *BEEP_BITS;
+
+	const u16 *REG_VIN;
+	const u16 *REG_IN_MINMAX[2];
+
+	const u16 *REG_TARGET;
+	const u16 *REG_FAN;
+	const u16 *REG_FAN_MODE;
+	const u16 *REG_FAN_MIN;
+	const u16 *REG_FAN_PULSES;
+	const u16 *FAN_PULSE_SHIFT;
+	const u16 *REG_FAN_TIME[3];
+
+	const u16 *REG_TOLERANCE_H;
+
+	const u8 *REG_PWM_MODE;
+	const u8 *PWM_MODE_MASK;
+
+	const u16 *REG_PWM[7];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+				 * [3]=pwm_max, [4]=pwm_step,
+				 * [5]=weight_duty_step, [6]=weight_duty_base
+				 */
+	const u16 *REG_PWM_READ;
+
+	const u16 *REG_CRITICAL_PWM_ENABLE;
+	u8 CRITICAL_PWM_ENABLE_MASK;
+	const u16 *REG_CRITICAL_PWM;
+
+	const u16 *REG_AUTO_TEMP;
+	const u16 *REG_AUTO_PWM;
+
+	const u16 *REG_CRITICAL_TEMP;
+	const u16 *REG_CRITICAL_TEMP_TOLERANCE;
+
+	const u16 *REG_TEMP_SOURCE;	/* temp register sources */
+	const u16 *REG_TEMP_SEL;
+	const u16 *REG_WEIGHT_TEMP_SEL;
+	const u16 *REG_WEIGHT_TEMP[3];	/* 0=base, 1=tolerance, 2=step */
+
+	const u16 *REG_TEMP_OFFSET;
+
+	const u16 *REG_ALARM;
+	const u16 *REG_BEEP;
+
+	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
+	struct mutex update_lock;
+	bool valid;		/* true if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* Register values */
+	u8 bank;		/* current register bank */
+	u8 in_num;		/* number of in inputs we have */
+	u8 in[15][3];		/* [0]=in, [1]=in_max, [2]=in_min */
+	unsigned int rpm[NUM_FAN];
+	u16 fan_min[NUM_FAN];
+	u8 fan_pulses[NUM_FAN];
+	u8 fan_div[NUM_FAN];
+	u8 has_pwm;
+	u8 has_fan;		/* some fan inputs can be disabled */
+	u8 has_fan_min;		/* some fans don't have min register */
+	bool has_fan_div;
+
+	u8 num_temp_alarms;	/* 2, 3, or 6 */
+	u8 num_temp_beeps;	/* 2, 3, or 6 */
+	u8 temp_fixed_num;	/* 3 or 6 */
+	u8 temp_type[NUM_TEMP_FIXED];
+	s8 temp_offset[NUM_TEMP_FIXED];
+	s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+				* 3=temp_crit, 4=temp_lcrit */
+	u64 alarms;
+	u64 beeps;
+
+	u8 pwm_num;	/* number of pwm */
+	u8 pwm_mode[NUM_FAN];	/* 1->DC variable voltage,
+				 * 0->PWM variable duty cycle
+				 */
+	enum pwm_enable pwm_enable[NUM_FAN];
+			/* 0->off
+			 * 1->manual
+			 * 2->thermal cruise mode (also called SmartFan I)
+			 * 3->fan speed cruise mode
+			 * 4->SmartFan III
+			 * 5->enhanced variable thermal cruise (SmartFan IV)
+			 */
+	u8 pwm[7][NUM_FAN];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+				 * [3]=pwm_max, [4]=pwm_step,
+				 * [5]=weight_duty_step, [6]=weight_duty_base
+				 */
+
+	u8 target_temp[NUM_FAN];
+	u8 target_temp_mask;
+	u32 target_speed[NUM_FAN];
+	u32 target_speed_tolerance[NUM_FAN];
+	u8 speed_tolerance_limit;
+
+	u8 temp_tolerance[2][NUM_FAN];
+	u8 tolerance_mask;
+
+	u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+
+	/* Automatic fan speed control registers */
+	int auto_pwm_num;
+	u8 auto_pwm[NUM_FAN][7];
+	u8 auto_temp[NUM_FAN][7];
+	u8 pwm_temp_sel[NUM_FAN];
+	u8 pwm_weight_temp_sel[NUM_FAN];
+	u8 weight_temp[3][NUM_FAN];	/* 0->temp_step, 1->temp_step_tol,
+					 * 2->temp_base
+					 */
+
+	u8 vid;
+	u8 vrm;
+
+	bool have_vid;
+
+	u16 have_temp;
+	u16 have_temp_fixed;
+	u16 have_in;
+
+	/* Remember extra register values over suspend/resume */
+	u8 vbat;
+	u8 fandiv1;
+	u8 fandiv2;
+	u8 sio_reg_enable;
+};
+
+struct nct6775_sio_data {
+	int sioreg;
+	enum kinds kind;
+};
+
+struct sensor_device_template {
+	struct device_attribute dev_attr;
+	union {
+		struct {
+			u8 nr;
+			u8 index;
+		} s;
+		int index;
+	} u;
+	bool s2;	/* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+	union {
+		struct sensor_device_attribute a1;
+		struct sensor_device_attribute_2 a2;
+	} u;
+	char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) {	\
+	.attr = {.name = _template, .mode = _mode },		\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index)	\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.index = _index,						\
+	  .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)				\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.s.index = _index,						\
+	  .u.s.nr = _nr,						\
+	  .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index)	\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store,	\
+				 _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store,	\
+			  _nr, _index)					\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)
+
+struct sensor_template_group {
+	struct sensor_device_template **templates;
+	umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+	int base;
+};
+
+static struct attribute_group *
+nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+			  int repeat)
+{
+	struct attribute_group *group;
+	struct sensor_device_attr_u *su;
+	struct sensor_device_attribute *a;
+	struct sensor_device_attribute_2 *a2;
+	struct attribute **attrs;
+	struct sensor_device_template **t;
+	int i, count;
+
+	if (repeat <= 0)
+		return ERR_PTR(-EINVAL);
+
+	t = tg->templates;
+	for (count = 0; *t; t++, count++)
+		;
+
+	if (count == 0)
+		return ERR_PTR(-EINVAL);
+
+	group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+	if (group == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+			     GFP_KERNEL);
+	if (attrs == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+			       GFP_KERNEL);
+	if (su == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	group->attrs = attrs;
+	group->is_visible = tg->is_visible;
+
+	for (i = 0; i < repeat; i++) {
+		t = tg->templates;
+		while (*t != NULL) {
+			snprintf(su->name, sizeof(su->name),
+				 (*t)->dev_attr.attr.name, tg->base + i);
+			if ((*t)->s2) {
+				a2 = &su->u.a2;
+				sysfs_attr_init(&a2->dev_attr.attr);
+				a2->dev_attr.attr.name = su->name;
+				a2->nr = (*t)->u.s.nr + i;
+				a2->index = (*t)->u.s.index;
+				a2->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a2->dev_attr.show = (*t)->dev_attr.show;
+				a2->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a2->dev_attr.attr;
+			} else {
+				a = &su->u.a1;
+				sysfs_attr_init(&a->dev_attr.attr);
+				a->dev_attr.attr.name = su->name;
+				a->index = (*t)->u.index + i;
+				a->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a->dev_attr.show = (*t)->dev_attr.show;
+				a->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a->dev_attr.attr;
+			}
+			attrs++;
+			su++;
+			t++;
+		}
+	}
+
+	return group;
+}
+
+static bool is_word_sized(struct nct6775_data *data, u16 reg)
+{
+	switch (data->kind) {
+	case nct6106:
+		return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+		  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
+		  reg == 0x111 || reg == 0x121 || reg == 0x131;
+	case nct6775:
+		return (((reg & 0xff00) == 0x100 ||
+		    (reg & 0xff00) == 0x200) &&
+		   ((reg & 0x00ff) == 0x50 ||
+		    (reg & 0x00ff) == 0x53 ||
+		    (reg & 0x00ff) == 0x55)) ||
+		  (reg & 0xfff0) == 0x630 ||
+		  reg == 0x640 || reg == 0x642 ||
+		  reg == 0x662 ||
+		  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+		  reg == 0x73 || reg == 0x75 || reg == 0x77;
+	case nct6776:
+		return (((reg & 0xff00) == 0x100 ||
+		    (reg & 0xff00) == 0x200) &&
+		   ((reg & 0x00ff) == 0x50 ||
+		    (reg & 0x00ff) == 0x53 ||
+		    (reg & 0x00ff) == 0x55)) ||
+		  (reg & 0xfff0) == 0x630 ||
+		  reg == 0x402 ||
+		  reg == 0x640 || reg == 0x642 ||
+		  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+		  reg == 0x73 || reg == 0x75 || reg == 0x77;
+	case nct6779:
+	case nct6791:
+	case nct6792:
+	case nct6793:
+		return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
+		  ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
+		  reg == 0x402 ||
+		  reg == 0x63a || reg == 0x63c || reg == 0x63e ||
+		  reg == 0x640 || reg == 0x642 ||
+		  reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
+		  reg == 0x7b || reg == 0x7d;
+	}
+	return false;
+}
+
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
+static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
+{
+	u8 bank = reg >> 8;
+
+	if (data->bank != bank) {
+		outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
+		outb_p(bank, data->addr + DATA_REG_OFFSET);
+		data->bank = bank;
+	}
+}
+
+static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
+{
+	int res, word_sized = is_word_sized(data, reg);
+
+	nct6775_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+	res = inb_p(data->addr + DATA_REG_OFFSET);
+	if (word_sized) {
+		outb_p((reg & 0xff) + 1,
+		       data->addr + ADDR_REG_OFFSET);
+		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
+	}
+	return res;
+}
+
+static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
+{
+	int word_sized = is_word_sized(data, reg);
+
+	nct6775_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+	if (word_sized) {
+		outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
+		outb_p((reg & 0xff) + 1,
+		       data->addr + ADDR_REG_OFFSET);
+	}
+	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+	return 0;
+}
+
+/* We left-align 8-bit temperature values to make the code simpler */
+static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
+{
+	u16 res;
+
+	res = nct6775_read_value(data, reg);
+	if (!is_word_sized(data, reg))
+		res <<= 8;
+
+	return res;
+}
+
+static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
+{
+	if (!is_word_sized(data, reg))
+		value >>= 8;
+	return nct6775_write_value(data, reg, value);
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+		    | (data->fan_div[0] & 0x7);
+		nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 1:
+		reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+		    | ((data->fan_div[1] << 4) & 0x70);
+		nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 2:
+		reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+		    | (data->fan_div[2] & 0x7);
+		nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	case 3:
+		reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+		    | ((data->fan_div[3] << 4) & 0x70);
+		nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	}
+}
+
+static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
+{
+	if (data->kind == nct6775)
+		nct6775_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct nct6775_data *data)
+{
+	u8 i;
+
+	i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+	data->fan_div[0] = i & 0x7;
+	data->fan_div[1] = (i & 0x70) >> 4;
+	i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+	data->fan_div[2] = i & 0x7;
+	if (data->has_fan & (1 << 3))
+		data->fan_div[3] = (i & 0x70) >> 4;
+}
+
+static void nct6775_update_fan_div_common(struct nct6775_data *data)
+{
+	if (data->kind == nct6775)
+		nct6775_update_fan_div(data);
+}
+
+static void nct6775_init_fan_div(struct nct6775_data *data)
+{
+	int i;
+
+	nct6775_update_fan_div_common(data);
+	/*
+	 * For all fans, start with highest divider value if the divider
+	 * register is not initialized. This ensures that we get a
+	 * reading from the fan count register, even if it is not optimal.
+	 * We'll compute a better divider later on.
+	 */
+	for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		if (data->fan_div[i] == 0) {
+			data->fan_div[i] = 7;
+			nct6775_write_fan_div_common(data, i);
+		}
+	}
+}
+
+static void nct6775_init_fan_common(struct device *dev,
+				    struct nct6775_data *data)
+{
+	int i;
+	u8 reg;
+
+	if (data->has_fan_div)
+		nct6775_init_fan_div(data);
+
+	/*
+	 * If fan_min is not set (0), set it to 0xff to disable it. This
+	 * prevents the unnecessary warning when fanX_min is reported as 0.
+	 */
+	for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+		if (data->has_fan_min & (1 << i)) {
+			reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
+			if (!reg)
+				nct6775_write_value(data, data->REG_FAN_MIN[i],
+						    data->has_fan_div ? 0xff
+								      : 0xff1f);
+		}
+	}
+}
+
+static void nct6775_select_fan_div(struct device *dev,
+				   struct nct6775_data *data, int nr, u16 reg)
+{
+	u8 fan_div = data->fan_div[nr];
+	u16 fan_min;
+
+	if (!data->has_fan_div)
+		return;
+
+	/*
+	 * If we failed to measure the fan speed, or the reported value is not
+	 * in the optimal range, and the clock divider can be modified,
+	 * let's try that for next time.
+	 */
+	if (reg == 0x00 && fan_div < 0x07)
+		fan_div++;
+	else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
+		fan_div--;
+
+	if (fan_div != data->fan_div[nr]) {
+		dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
+			nr + 1, div_from_reg(data->fan_div[nr]),
+			div_from_reg(fan_div));
+
+		/* Preserve min limit if possible */
+		if (data->has_fan_min & (1 << nr)) {
+			fan_min = data->fan_min[nr];
+			if (fan_div > data->fan_div[nr]) {
+				if (fan_min != 255 && fan_min > 1)
+					fan_min >>= 1;
+			} else {
+				if (fan_min != 255) {
+					fan_min <<= 1;
+					if (fan_min > 254)
+						fan_min = 254;
+				}
+			}
+			if (fan_min != data->fan_min[nr]) {
+				data->fan_min[nr] = fan_min;
+				nct6775_write_value(data, data->REG_FAN_MIN[nr],
+						    fan_min);
+			}
+		}
+		data->fan_div[nr] = fan_div;
+		nct6775_write_fan_div_common(data, nr);
+	}
+}
+
+static void nct6775_update_pwm(struct device *dev)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int i, j;
+	int fanmodecfg, reg;
+	bool duty_is_dc;
+
+	for (i = 0; i < data->pwm_num; i++) {
+		if (!(data->has_pwm & (1 << i)))
+			continue;
+
+		duty_is_dc = data->REG_PWM_MODE[i] &&
+		  (nct6775_read_value(data, data->REG_PWM_MODE[i])
+		   & data->PWM_MODE_MASK[i]);
+		data->pwm_mode[i] = duty_is_dc;
+
+		fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
+		for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
+			if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
+				data->pwm[j][i]
+				  = nct6775_read_value(data,
+						       data->REG_PWM[j][i]);
+			}
+		}
+
+		data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
+							(fanmodecfg >> 4) & 7);
+
+		if (!data->temp_tolerance[0][i] ||
+		    data->pwm_enable[i] != speed_cruise)
+			data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
+		if (!data->target_speed_tolerance[i] ||
+		    data->pwm_enable[i] == speed_cruise) {
+			u8 t = fanmodecfg & 0x0f;
+
+			if (data->REG_TOLERANCE_H) {
+				t |= (nct6775_read_value(data,
+				      data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
+			}
+			data->target_speed_tolerance[i] = t;
+		}
+
+		data->temp_tolerance[1][i] =
+			nct6775_read_value(data,
+					data->REG_CRITICAL_TEMP_TOLERANCE[i]);
+
+		reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
+		data->pwm_temp_sel[i] = reg & 0x1f;
+		/* If fan can stop, report floor as 0 */
+		if (reg & 0x80)
+			data->pwm[2][i] = 0;
+
+		if (!data->REG_WEIGHT_TEMP_SEL[i])
+			continue;
+
+		reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
+		data->pwm_weight_temp_sel[i] = reg & 0x1f;
+		/* If weight is disabled, report weight source as 0 */
+		if (j == 1 && !(reg & 0x80))
+			data->pwm_weight_temp_sel[i] = 0;
+
+		/* Weight temp data */
+		for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
+			data->weight_temp[j][i]
+			  = nct6775_read_value(data,
+					       data->REG_WEIGHT_TEMP[j][i]);
+		}
+	}
+}
+
+static void nct6775_update_pwm_limits(struct device *dev)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int i, j;
+	u8 reg;
+	u16 reg_t;
+
+	for (i = 0; i < data->pwm_num; i++) {
+		if (!(data->has_pwm & (1 << i)))
+			continue;
+
+		for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
+			data->fan_time[j][i] =
+			  nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
+		}
+
+		reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
+		/* Update only in matching mode or if never updated */
+		if (!data->target_temp[i] ||
+		    data->pwm_enable[i] == thermal_cruise)
+			data->target_temp[i] = reg_t & data->target_temp_mask;
+		if (!data->target_speed[i] ||
+		    data->pwm_enable[i] == speed_cruise) {
+			if (data->REG_TOLERANCE_H) {
+				reg_t |= (nct6775_read_value(data,
+					data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
+			}
+			data->target_speed[i] = reg_t;
+		}
+
+		for (j = 0; j < data->auto_pwm_num; j++) {
+			data->auto_pwm[i][j] =
+			  nct6775_read_value(data,
+					     NCT6775_AUTO_PWM(data, i, j));
+			data->auto_temp[i][j] =
+			  nct6775_read_value(data,
+					     NCT6775_AUTO_TEMP(data, i, j));
+		}
+
+		/* critical auto_pwm temperature data */
+		data->auto_temp[i][data->auto_pwm_num] =
+			nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
+
+		switch (data->kind) {
+		case nct6775:
+			reg = nct6775_read_value(data,
+						 NCT6775_REG_CRITICAL_ENAB[i]);
+			data->auto_pwm[i][data->auto_pwm_num] =
+						(reg & 0x02) ? 0xff : 0x00;
+			break;
+		case nct6776:
+			data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+			break;
+		case nct6106:
+		case nct6779:
+		case nct6791:
+		case nct6792:
+		case nct6793:
+			reg = nct6775_read_value(data,
+					data->REG_CRITICAL_PWM_ENABLE[i]);
+			if (reg & data->CRITICAL_PWM_ENABLE_MASK)
+				reg = nct6775_read_value(data,
+					data->REG_CRITICAL_PWM[i]);
+			else
+				reg = 0xff;
+			data->auto_pwm[i][data->auto_pwm_num] = reg;
+			break;
+		}
+	}
+}
+
+static struct nct6775_data *nct6775_update_device(struct device *dev)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int i, j;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		/* Fan clock dividers */
+		nct6775_update_fan_div_common(data);
+
+		/* Measured voltages and limits */
+		for (i = 0; i < data->in_num; i++) {
+			if (!(data->have_in & (1 << i)))
+				continue;
+
+			data->in[i][0] = nct6775_read_value(data,
+							    data->REG_VIN[i]);
+			data->in[i][1] = nct6775_read_value(data,
+					  data->REG_IN_MINMAX[0][i]);
+			data->in[i][2] = nct6775_read_value(data,
+					  data->REG_IN_MINMAX[1][i]);
+		}
+
+		/* Measured fan speeds and limits */
+		for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
+			u16 reg;
+
+			if (!(data->has_fan & (1 << i)))
+				continue;
+
+			reg = nct6775_read_value(data, data->REG_FAN[i]);
+			data->rpm[i] = data->fan_from_reg(reg,
+							  data->fan_div[i]);
+
+			if (data->has_fan_min & (1 << i))
+				data->fan_min[i] = nct6775_read_value(data,
+					   data->REG_FAN_MIN[i]);
+			data->fan_pulses[i] =
+			  (nct6775_read_value(data, data->REG_FAN_PULSES[i])
+				>> data->FAN_PULSE_SHIFT[i]) & 0x03;
+
+			nct6775_select_fan_div(dev, data, i, reg);
+		}
+
+		nct6775_update_pwm(dev);
+		nct6775_update_pwm_limits(dev);
+
+		/* Measured temperatures and limits */
+		for (i = 0; i < NUM_TEMP; i++) {
+			if (!(data->have_temp & (1 << i)))
+				continue;
+			for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
+				if (data->reg_temp[j][i])
+					data->temp[j][i]
+					  = nct6775_read_temp(data,
+						data->reg_temp[j][i]);
+			}
+			if (i >= NUM_TEMP_FIXED ||
+			    !(data->have_temp_fixed & (1 << i)))
+				continue;
+			data->temp_offset[i]
+			  = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
+		}
+
+		data->alarms = 0;
+		for (i = 0; i < NUM_REG_ALARM; i++) {
+			u8 alarm;
+
+			if (!data->REG_ALARM[i])
+				continue;
+			alarm = nct6775_read_value(data, data->REG_ALARM[i]);
+			data->alarms |= ((u64)alarm) << (i << 3);
+		}
+
+		data->beeps = 0;
+		for (i = 0; i < NUM_REG_BEEP; i++) {
+			u8 beep;
+
+			if (!data->REG_BEEP[i])
+				continue;
+			beep = nct6775_read_value(data, data->REG_BEEP[i]);
+			data->beeps |= ((u64)beep) << (i << 3);
+		}
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+static ssize_t
+show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int index = sattr->index;
+	int nr = sattr->nr;
+
+	return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
+}
+
+static ssize_t
+store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
+	     size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int index = sattr->index;
+	int nr = sattr->nr;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	mutex_lock(&data->update_lock);
+	data->in[nr][index] = in_to_reg(val, nr);
+	nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
+			    data->in[nr][index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = data->ALARM_BITS[sattr->index];
+
+	return sprintf(buf, "%u\n",
+		       (unsigned int)((data->alarms >> nr) & 0x01));
+}
+
+static int find_temp_source(struct nct6775_data *data, int index, int count)
+{
+	int source = data->temp_src[index];
+	int nr;
+
+	for (nr = 0; nr < count; nr++) {
+		int src;
+
+		src = nct6775_read_value(data,
+					 data->REG_TEMP_SOURCE[nr]) & 0x1f;
+		if (src == source)
+			return nr;
+	}
+	return -ENODEV;
+}
+
+static ssize_t
+show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6775_data *data = nct6775_update_device(dev);
+	unsigned int alarm = 0;
+	int nr;
+
+	/*
+	 * For temperatures, there is no fixed mapping from registers to alarm
+	 * bits. Alarm bits are determined by the temperature source mapping.
+	 */
+	nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
+	if (nr >= 0) {
+		int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
+
+		alarm = (data->alarms >> bit) & 0x01;
+	}
+	return sprintf(buf, "%u\n", alarm);
+}
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6775_data *data = nct6775_update_device(dev);
+	int nr = data->BEEP_BITS[sattr->index];
+
+	return sprintf(buf, "%u\n",
+		       (unsigned int)((data->beeps >> nr) & 0x01));
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+	   size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int nr = data->BEEP_BITS[sattr->index];
+	int regindex = nr >> 3;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->beeps |= (1ULL << nr);
+	else
+		data->beeps &= ~(1ULL << nr);
+	nct6775_write_value(data, data->REG_BEEP[regindex],
+			    (data->beeps >> (regindex << 3)) & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6775_data *data = nct6775_update_device(dev);
+	unsigned int beep = 0;
+	int nr;
+
+	/*
+	 * For temperatures, there is no fixed mapping from registers to beep
+	 * enable bits. Beep enable bits are determined by the temperature
+	 * source mapping.
+	 */
+	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+	if (nr >= 0) {
+		int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+
+		beep = (data->beeps >> bit) & 0x01;
+	}
+	return sprintf(buf, "%u\n", beep);
+}
+
+static ssize_t
+store_temp_beep(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int nr, bit, regindex;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 1)
+		return -EINVAL;
+
+	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+	if (nr < 0)
+		return nr;
+
+	bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+	regindex = bit >> 3;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->beeps |= (1ULL << bit);
+	else
+		data->beeps &= ~(1ULL << bit);
+	nct6775_write_value(data, data->REG_BEEP[regindex],
+			    (data->beeps >> (regindex << 3)) & 0xff);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static umode_t nct6775_in_is_visible(struct kobject *kobj,
+				     struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int in = index / 5;	/* voltage index */
+
+	if (!(data->have_in & (1 << in)))
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
+SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
+		0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
+		  store_in_reg, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
+		  store_in_reg, 0, 2);
+
+/*
+ * nct6775_in_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_in_template[] = {
+	&sensor_dev_template_in_input,
+	&sensor_dev_template_in_alarm,
+	&sensor_dev_template_in_beep,
+	&sensor_dev_template_in_min,
+	&sensor_dev_template_in_max,
+	NULL
+};
+
+static struct sensor_template_group nct6775_in_template_group = {
+	.templates = nct6775_attributes_in_template,
+	.is_visible = nct6775_in_is_visible,
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%d\n", data->rpm[nr]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%d\n",
+		       data->fan_from_reg_min(data->fan_min[nr],
+					      data->fan_div[nr]));
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	unsigned int reg;
+	u8 new_div;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (!data->has_fan_div) {
+		/* NCT6776F or NCT6779D; we know this is a 13 bit register */
+		if (!val) {
+			val = 0xff1f;
+		} else {
+			if (val > 1350000U)
+				val = 135000U;
+			val = 1350000U / val;
+			val = (val & 0x1f) | ((val << 3) & 0xff00);
+		}
+		data->fan_min[nr] = val;
+		goto write_min;	/* Leave fan divider alone */
+	}
+	if (!val) {
+		/* No min limit, alarm disabled */
+		data->fan_min[nr] = 255;
+		new_div = data->fan_div[nr]; /* No change */
+		dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
+		goto write_div;
+	}
+	reg = 1350000U / val;
+	if (reg >= 128 * 255) {
+		/*
+		 * Speed below this value cannot possibly be represented,
+		 * even with the highest divider (128)
+		 */
+		data->fan_min[nr] = 254;
+		new_div = 7; /* 128 == (1 << 7) */
+		dev_warn(dev,
+			 "fan%u low limit %lu below minimum %u, set to minimum\n",
+			 nr + 1, val, data->fan_from_reg_min(254, 7));
+	} else if (!reg) {
+		/*
+		 * Speed above this value cannot possibly be represented,
+		 * even with the lowest divider (1)
+		 */
+		data->fan_min[nr] = 1;
+		new_div = 0; /* 1 == (1 << 0) */
+		dev_warn(dev,
+			 "fan%u low limit %lu above maximum %u, set to maximum\n",
+			 nr + 1, val, data->fan_from_reg_min(1, 0));
+	} else {
+		/*
+		 * Automatically pick the best divider, i.e. the one such
+		 * that the min limit will correspond to a register value
+		 * in the 96..192 range
+		 */
+		new_div = 0;
+		while (reg > 192 && new_div < 7) {
+			reg >>= 1;
+			new_div++;
+		}
+		data->fan_min[nr] = reg;
+	}
+
+write_div:
+	/*
+	 * Write both the fan clock divider (if it changed) and the new
+	 * fan min (unconditionally)
+	 */
+	if (new_div != data->fan_div[nr]) {
+		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+			nr + 1, div_from_reg(data->fan_div[nr]),
+			div_from_reg(new_div));
+		data->fan_div[nr] = new_div;
+		nct6775_write_fan_div_common(data, nr);
+		/* Give the chip time to sample a new speed value */
+		data->last_updated = jiffies;
+	}
+
+write_min:
+	nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int p = data->fan_pulses[sattr->index];
+
+	return sprintf(buf, "%d\n", p ? : 4);
+}
+
+static ssize_t
+store_fan_pulses(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val > 4)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->fan_pulses[nr] = val & 3;
+	reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
+	reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
+	reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
+	nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static umode_t nct6775_fan_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int fan = index / 6;	/* fan index */
+	int nr = index % 6;	/* attribute index */
+
+	if (!(data->has_fan & (1 << fan)))
+		return 0;
+
+	if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
+		return 0;
+	if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
+		return 0;
+	if (nr == 4 && !(data->has_fan_min & (1 << fan)))
+		return 0;
+	if (nr == 5 && data->kind != nct6775)
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
+		FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
+		store_beep, FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
+		store_fan_pulses, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
+		store_fan_min, 0);
+SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
+
+/*
+ * nct6775_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_fan_template[] = {
+	&sensor_dev_template_fan_input,
+	&sensor_dev_template_fan_alarm,	/* 1 */
+	&sensor_dev_template_fan_beep,	/* 2 */
+	&sensor_dev_template_fan_pulses,
+	&sensor_dev_template_fan_min,	/* 4 */
+	&sensor_dev_template_fan_div,	/* 5 */
+	NULL
+};
+
+static struct sensor_template_group nct6775_fan_template_group = {
+	.templates = nct6775_attributes_fan_template,
+	.is_visible = nct6775_fan_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
+	   size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	int err;
+	long val;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[index][nr] = LM75_TEMP_TO_REG(val);
+	nct6775_write_temp(data, data->reg_temp[index][nr],
+			   data->temp[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+	return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
+}
+
+static ssize_t
+store_temp_offset(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp_offset[nr] = val;
+	nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
+static ssize_t
+store_temp_type(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	u8 vbat, diode, vbit, dbit;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val != 1 && val != 3 && val != 4)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	data->temp_type[nr] = val;
+	vbit = 0x02 << nr;
+	dbit = data->DIODE_MASK << nr;
+	vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
+	diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
+	switch (val) {
+	case 1:	/* CPU diode (diode, current mode) */
+		vbat |= vbit;
+		diode |= dbit;
+		break;
+	case 3: /* diode, voltage mode */
+		vbat |= dbit;
+		break;
+	case 4:	/* thermistor */
+		break;
+	}
+	nct6775_write_value(data, data->REG_VBAT, vbat);
+	nct6775_write_value(data, data->REG_DIODE, diode);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static umode_t nct6775_temp_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int temp = index / 10;	/* temp index */
+	int nr = index % 10;	/* attribute index */
+
+	if (!(data->have_temp & (1 << temp)))
+		return 0;
+
+	if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
+		return 0;				/* alarm */
+
+	if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
+		return 0;				/* beep */
+
+	if (nr == 4 && !data->reg_temp[1][temp])	/* max */
+		return 0;
+
+	if (nr == 5 && !data->reg_temp[2][temp])	/* max_hyst */
+		return 0;
+
+	if (nr == 6 && !data->reg_temp[3][temp])	/* crit */
+		return 0;
+
+	if (nr == 7 && !data->reg_temp[4][temp])	/* lcrit */
+		return 0;
+
+	/* offset and type only apply to fixed sensors */
+	if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 1);
+SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
+		  show_temp, store_temp, 0, 2);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 3);
+SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 4);
+SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
+		show_temp_offset, store_temp_offset, 0);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
+		store_temp_type, 0);
+SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
+SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
+		store_temp_beep, 0);
+
+/*
+ * nct6775_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_temp_template[] = {
+	&sensor_dev_template_temp_input,
+	&sensor_dev_template_temp_label,
+	&sensor_dev_template_temp_alarm,	/* 2 */
+	&sensor_dev_template_temp_beep,		/* 3 */
+	&sensor_dev_template_temp_max,		/* 4 */
+	&sensor_dev_template_temp_max_hyst,	/* 5 */
+	&sensor_dev_template_temp_crit,		/* 6 */
+	&sensor_dev_template_temp_lcrit,	/* 7 */
+	&sensor_dev_template_temp_offset,	/* 8 */
+	&sensor_dev_template_temp_type,		/* 9 */
+	NULL
+};
+
+static struct sensor_template_group nct6775_temp_template_group = {
+	.templates = nct6775_attributes_temp_template,
+	.is_visible = nct6775_temp_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+	return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	/* Setting DC mode is not supported for all chips/channels */
+	if (data->REG_PWM_MODE[nr] == 0) {
+		if (val)
+			return -EINVAL;
+		return count;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->pwm_mode[nr] = val;
+	reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
+	reg &= ~data->PWM_MODE_MASK[nr];
+	if (val)
+		reg |= data->PWM_MODE_MASK[nr];
+	nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	int pwm;
+
+	/*
+	 * For automatic fan control modes, show current pwm readings.
+	 * Otherwise, show the configured value.
+	 */
+	if (index == 0 && data->pwm_enable[nr] > manual)
+		pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
+	else
+		pwm = data->pwm[index][nr];
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+	  size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	unsigned long val;
+	int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
+	int maxval[7]
+	  = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
+	int err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	val = clamp_val(val, minval[index], maxval[index]);
+
+	mutex_lock(&data->update_lock);
+	data->pwm[index][nr] = val;
+	nct6775_write_value(data, data->REG_PWM[index][nr], val);
+	if (index == 2)	{ /* floor: disable if val == 0 */
+		reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+		reg &= 0x7f;
+		if (val)
+			reg |= 0x80;
+		nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* Returns 0 if OK, -EINVAL otherwise */
+static int check_trip_points(struct nct6775_data *data, int nr)
+{
+	int i;
+
+	for (i = 0; i < data->auto_pwm_num - 1; i++) {
+		if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+			return -EINVAL;
+	}
+	for (i = 0; i < data->auto_pwm_num - 1; i++) {
+		if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
+			return -EINVAL;
+	}
+	/* validate critical temperature and pwm if enabled (pwm > 0) */
+	if (data->auto_pwm[nr][data->auto_pwm_num]) {
+		if (data->auto_temp[nr][data->auto_pwm_num - 1] >
+				data->auto_temp[nr][data->auto_pwm_num] ||
+		    data->auto_pwm[nr][data->auto_pwm_num - 1] >
+				data->auto_pwm[nr][data->auto_pwm_num])
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static void pwm_update_registers(struct nct6775_data *data, int nr)
+{
+	u8 reg;
+
+	switch (data->pwm_enable[nr]) {
+	case off:
+	case manual:
+		break;
+	case speed_cruise:
+		reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+		reg = (reg & ~data->tolerance_mask) |
+		  (data->target_speed_tolerance[nr] & data->tolerance_mask);
+		nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+		nct6775_write_value(data, data->REG_TARGET[nr],
+				    data->target_speed[nr] & 0xff);
+		if (data->REG_TOLERANCE_H) {
+			reg = (data->target_speed[nr] >> 8) & 0x0f;
+			reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
+			nct6775_write_value(data,
+					    data->REG_TOLERANCE_H[nr],
+					    reg);
+		}
+		break;
+	case thermal_cruise:
+		nct6775_write_value(data, data->REG_TARGET[nr],
+				    data->target_temp[nr]);
+		/* intentional */
+	default:
+		reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+		reg = (reg & ~data->tolerance_mask) |
+		  data->temp_tolerance[0][nr];
+		nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+		break;
+	}
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+	return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	u16 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val > sf4)
+		return -EINVAL;
+
+	if (val == sf3 && data->kind != nct6775)
+		return -EINVAL;
+
+	if (val == sf4 && check_trip_points(data, nr)) {
+		dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
+		dev_err(dev, "Adjust trip points and try again\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable[nr] = val;
+	if (val == off) {
+		/*
+		 * turn off pwm control: select manual mode, set pwm to maximum
+		 */
+		data->pwm[0][nr] = 255;
+		nct6775_write_value(data, data->REG_PWM[0][nr], 255);
+	}
+	pwm_update_registers(data, nr);
+	reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+	reg &= 0x0f;
+	reg |= pwm_enable_to_reg(val) << 4;
+	nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
+{
+	int i, sel = 0;
+
+	for (i = 0; i < NUM_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		if (src == data->temp_src[i]) {
+			sel = i + 1;
+			break;
+		}
+	}
+
+	return sprintf(buf, "%d\n", sel);
+}
+
+static ssize_t
+show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int index = sattr->index;
+
+	return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
+		   const char *buf, size_t count)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err, reg, src;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val == 0 || val > NUM_TEMP)
+		return -EINVAL;
+	if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	src = data->temp_src[val - 1];
+	data->pwm_temp_sel[nr] = src;
+	reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+	reg &= 0xe0;
+	reg |= src;
+	nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int index = sattr->index;
+
+	return show_pwm_temp_sel_common(data, buf,
+					data->pwm_weight_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err, reg, src;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > NUM_TEMP)
+		return -EINVAL;
+	if (val && (!(data->have_temp & (1 << (val - 1))) ||
+		    !data->temp_src[val - 1]))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (val) {
+		src = data->temp_src[val - 1];
+		data->pwm_weight_temp_sel[nr] = src;
+		reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+		reg &= 0xe0;
+		reg |= (src | 0x80);
+		nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+	} else {
+		data->pwm_weight_temp_sel[nr] = 0;
+		reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+		reg &= 0x7f;
+		nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+	return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
+}
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
+			data->target_temp_mask);
+
+	mutex_lock(&data->update_lock);
+	data->target_temp[nr] = val;
+	pwm_update_registers(data, nr);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+
+	return sprintf(buf, "%d\n",
+		       fan_from_reg16(data->target_speed[nr],
+				      data->fan_div[nr]));
+}
+
+static ssize_t
+store_target_speed(struct device *dev, struct device_attribute *attr,
+		   const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	u16 speed;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(val, 0, 1350000U);
+	speed = fan_to_reg(val, data->fan_div[nr]);
+
+	mutex_lock(&data->update_lock);
+	data->target_speed[nr] = speed;
+	pwm_update_registers(data, nr);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp_tolerance(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
+}
+
+static ssize_t
+store_temp_tolerance(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* Limit tolerance as needed */
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
+
+	mutex_lock(&data->update_lock);
+	data->temp_tolerance[index][nr] = val;
+	if (index)
+		pwm_update_registers(data, nr);
+	else
+		nct6775_write_value(data,
+				    data->REG_CRITICAL_TEMP_TOLERANCE[nr],
+				    val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Fan speed tolerance is a tricky beast, since the associated register is
+ * a tick counter, but the value is reported and configured as rpm.
+ * Compute resulting low and high rpm values and report the difference.
+ */
+static ssize_t
+show_speed_tolerance(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
+	int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
+	int tolerance;
+
+	if (low <= 0)
+		low = 1;
+	if (high > 0xffff)
+		high = 0xffff;
+	if (high < low)
+		high = low;
+
+	tolerance = (fan_from_reg16(low, data->fan_div[nr])
+		     - fan_from_reg16(high, data->fan_div[nr])) / 2;
+
+	return sprintf(buf, "%d\n", tolerance);
+}
+
+static ssize_t
+store_speed_tolerance(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	int nr = sattr->index;
+	unsigned long val;
+	int err;
+	int low, high;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	high = fan_from_reg16(data->target_speed[nr],
+			      data->fan_div[nr]) + val;
+	low = fan_from_reg16(data->target_speed[nr],
+			     data->fan_div[nr]) - val;
+	if (low <= 0)
+		low = 1;
+	if (high < low)
+		high = low;
+
+	val = (fan_to_reg(low, data->fan_div[nr]) -
+	       fan_to_reg(high, data->fan_div[nr])) / 2;
+
+	/* Limit tolerance as needed */
+	val = clamp_val(val, 0, data->speed_tolerance_limit);
+
+	mutex_lock(&data->update_lock);
+	data->target_speed_tolerance[nr] = val;
+	pwm_update_registers(data, nr);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
+		store_pwm_mode, 0);
+SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
+		store_pwm_enable, 0);
+SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
+		show_pwm_temp_sel, store_pwm_temp_sel, 0);
+SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
+		show_target_temp, store_target_temp, 0);
+SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
+		show_target_speed, store_target_speed, 0);
+SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
+		show_speed_tolerance, store_speed_tolerance, 0);
+
+/* Smart Fan registers */
+
+static ssize_t
+show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
+}
+
+static ssize_t
+store_weight_temp(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->weight_temp[index][nr] = val;
+	nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
+		  show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
+SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
+		  S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
+		  S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
+
+static ssize_t
+show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+
+	return sprintf(buf, "%d\n",
+		       step_time_from_reg(data->fan_time[index][nr],
+					  data->pwm_mode[nr]));
+}
+
+static ssize_t
+store_fan_time(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int index = sattr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = step_time_to_reg(val, data->pwm_mode[nr]);
+	mutex_lock(&data->update_lock);
+	data->fan_time[index][nr] = val;
+	nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
+}
+
+static ssize_t
+store_auto_pwm(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int point = sattr->index;
+	unsigned long val;
+	int err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 255)
+		return -EINVAL;
+
+	if (point == data->auto_pwm_num) {
+		if (data->kind != nct6775 && !val)
+			return -EINVAL;
+		if (data->kind != nct6779 && val)
+			val = 0xff;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->auto_pwm[nr][point] = val;
+	if (point < data->auto_pwm_num) {
+		nct6775_write_value(data,
+				    NCT6775_AUTO_PWM(data, nr, point),
+				    data->auto_pwm[nr][point]);
+	} else {
+		switch (data->kind) {
+		case nct6775:
+			/* disable if needed (pwm == 0) */
+			reg = nct6775_read_value(data,
+						 NCT6775_REG_CRITICAL_ENAB[nr]);
+			if (val)
+				reg |= 0x02;
+			else
+				reg &= ~0x02;
+			nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
+					    reg);
+			break;
+		case nct6776:
+			break; /* always enabled, nothing to do */
+		case nct6106:
+		case nct6779:
+		case nct6791:
+		case nct6792:
+		case nct6793:
+			nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
+					    val);
+			reg = nct6775_read_value(data,
+					data->REG_CRITICAL_PWM_ENABLE[nr]);
+			if (val == 255)
+				reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
+			else
+				reg |= data->CRITICAL_PWM_ENABLE_MASK;
+			nct6775_write_value(data,
+					    data->REG_CRITICAL_PWM_ENABLE[nr],
+					    reg);
+			break;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int point = sattr->index;
+
+	/*
+	 * We don't know for sure if the temperature is signed or unsigned.
+	 * Assume it is unsigned.
+	 */
+	return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
+}
+
+static ssize_t
+store_auto_temp(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int nr = sattr->nr;
+	int point = sattr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val > 255000)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
+	if (point < data->auto_pwm_num) {
+		nct6775_write_value(data,
+				    NCT6775_AUTO_TEMP(data, nr, point),
+				    data->auto_temp[nr][point]);
+	} else {
+		nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
+				    data->auto_temp[nr][point]);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int pwm = index / 36;	/* pwm index */
+	int nr = index % 36;	/* attribute index */
+
+	if (!(data->has_pwm & (1 << pwm)))
+		return 0;
+
+	if ((nr >= 14 && nr <= 18) || nr == 21)   /* weight */
+		if (!data->REG_WEIGHT_TEMP_SEL[pwm])
+			return 0;
+	if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
+		return 0;
+	if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
+		return 0;
+	if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
+		return 0;
+
+	if (nr >= 22 && nr <= 35) {		/* auto point */
+		int api = (nr - 22) / 2;	/* auto point index */
+
+		if (api > data->auto_pwm_num)
+			return 0;
+	}
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 0);
+SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 1);
+SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 2);
+SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
+		  show_temp_tolerance, store_temp_tolerance, 0, 0);
+SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
+		  S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
+		  0, 1);
+
+SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+		  0, 3);
+
+SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
+SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
+
+SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
+
+SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
+SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
+SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
+
+SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
+SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
+
+/*
+ * nct6775_pwm_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
+	&sensor_dev_template_pwm,
+	&sensor_dev_template_pwm_mode,
+	&sensor_dev_template_pwm_enable,
+	&sensor_dev_template_pwm_temp_sel,
+	&sensor_dev_template_pwm_temp_tolerance,
+	&sensor_dev_template_pwm_crit_temp_tolerance,
+	&sensor_dev_template_pwm_target_temp,
+	&sensor_dev_template_fan_target,
+	&sensor_dev_template_fan_tolerance,
+	&sensor_dev_template_pwm_stop_time,
+	&sensor_dev_template_pwm_step_up_time,
+	&sensor_dev_template_pwm_step_down_time,
+	&sensor_dev_template_pwm_start,
+	&sensor_dev_template_pwm_floor,
+	&sensor_dev_template_pwm_weight_temp_sel,	/* 14 */
+	&sensor_dev_template_pwm_weight_temp_step,
+	&sensor_dev_template_pwm_weight_temp_step_tol,
+	&sensor_dev_template_pwm_weight_temp_step_base,
+	&sensor_dev_template_pwm_weight_duty_step,	/* 18 */
+	&sensor_dev_template_pwm_max,			/* 19 */
+	&sensor_dev_template_pwm_step,			/* 20 */
+	&sensor_dev_template_pwm_weight_duty_base,	/* 21 */
+	&sensor_dev_template_pwm_auto_point1_pwm,	/* 22 */
+	&sensor_dev_template_pwm_auto_point1_temp,
+	&sensor_dev_template_pwm_auto_point2_pwm,
+	&sensor_dev_template_pwm_auto_point2_temp,
+	&sensor_dev_template_pwm_auto_point3_pwm,
+	&sensor_dev_template_pwm_auto_point3_temp,
+	&sensor_dev_template_pwm_auto_point4_pwm,
+	&sensor_dev_template_pwm_auto_point4_temp,
+	&sensor_dev_template_pwm_auto_point5_pwm,
+	&sensor_dev_template_pwm_auto_point5_temp,
+	&sensor_dev_template_pwm_auto_point6_pwm,
+	&sensor_dev_template_pwm_auto_point6_temp,
+	&sensor_dev_template_pwm_auto_point7_pwm,
+	&sensor_dev_template_pwm_auto_point7_temp,	/* 35 */
+
+	NULL
+};
+
+static struct sensor_template_group nct6775_pwm_template_group = {
+	.templates = nct6775_attributes_pwm_template,
+	.is_visible = nct6775_pwm_is_visible,
+	.base = 1,
+};
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* Case open detection */
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
+	unsigned long val;
+	u8 reg;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val) || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+
+	/*
+	 * Use CR registers to clear caseopen status.
+	 * The CR registers are the same for all chips, and not all chips
+	 * support clearing the caseopen status through "regular" registers.
+	 */
+	ret = superio_enter(data->sioreg);
+	if (ret) {
+		count = ret;
+		goto error;
+	}
+
+	superio_select(data->sioreg, NCT6775_LD_ACPI);
+	reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+	reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+	superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+	reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+	superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+	superio_exit(data->sioreg);
+
+	data->valid = false;	/* Force cache refresh */
+error:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+			  clear_caseopen, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+			  clear_caseopen, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, BEEP_ENABLE_BASE);
+
+static umode_t nct6775_other_is_visible(struct kobject *kobj,
+					struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+
+	if (index == 0 && !data->have_vid)
+		return 0;
+
+	if (index == 1 || index == 2) {
+		if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
+			return 0;
+	}
+
+	if (index == 3 || index == 4) {
+		if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
+			return 0;
+	}
+
+	return attr->mode;
+}
+
+/*
+ * nct6775_other_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct attribute *nct6775_attributes_other[] = {
+	&dev_attr_cpu0_vid.attr,				/* 0 */
+	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,	/* 1 */
+	&sensor_dev_attr_intrusion1_alarm.dev_attr.attr,	/* 2 */
+	&sensor_dev_attr_intrusion0_beep.dev_attr.attr,		/* 3 */
+	&sensor_dev_attr_intrusion1_beep.dev_attr.attr,		/* 4 */
+	&sensor_dev_attr_beep_enable.dev_attr.attr,		/* 5 */
+
+	NULL
+};
+
+static const struct attribute_group nct6775_group_other = {
+	.attrs = nct6775_attributes_other,
+	.is_visible = nct6775_other_is_visible,
+};
+
+static inline void nct6775_init_device(struct nct6775_data *data)
+{
+	int i;
+	u8 tmp, diode;
+
+	/* Start monitoring if needed */
+	if (data->REG_CONFIG) {
+		tmp = nct6775_read_value(data, data->REG_CONFIG);
+		if (!(tmp & 0x01))
+			nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
+	}
+
+	/* Enable temperature sensors if needed */
+	for (i = 0; i < NUM_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		if (!data->reg_temp_config[i])
+			continue;
+		tmp = nct6775_read_value(data, data->reg_temp_config[i]);
+		if (tmp & 0x01)
+			nct6775_write_value(data, data->reg_temp_config[i],
+					    tmp & 0xfe);
+	}
+
+	/* Enable VBAT monitoring if needed */
+	tmp = nct6775_read_value(data, data->REG_VBAT);
+	if (!(tmp & 0x01))
+		nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
+
+	diode = nct6775_read_value(data, data->REG_DIODE);
+
+	for (i = 0; i < data->temp_fixed_num; i++) {
+		if (!(data->have_temp_fixed & (1 << i)))
+			continue;
+		if ((tmp & (data->DIODE_MASK << i)))	/* diode */
+			data->temp_type[i]
+			  = 3 - ((diode >> i) & data->DIODE_MASK);
+		else				/* thermistor */
+			data->temp_type[i] = 4;
+	}
+}
+
+static void
+nct6775_check_fan_inputs(struct nct6775_data *data)
+{
+	bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
+	bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
+	int sioreg = data->sioreg;
+	int regval;
+
+	/* Store SIO_REG_ENABLE for use during resume */
+	superio_select(sioreg, NCT6775_LD_HWM);
+	data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
+
+	/* fan4 and fan5 share some pins with the GPIO and serial flash */
+	if (data->kind == nct6775) {
+		regval = superio_inb(sioreg, 0x2c);
+
+		fan3pin = regval & (1 << 6);
+		pwm3pin = regval & (1 << 7);
+
+		/* On NCT6775, fan4 shares pins with the fdc interface */
+		fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
+		fan4min = false;
+		fan5pin = false;
+		fan6pin = false;
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
+	} else if (data->kind == nct6776) {
+		bool gpok = superio_inb(sioreg, 0x27) & 0x80;
+		const char *board_vendor, *board_name;
+
+		board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+		board_name = dmi_get_system_info(DMI_BOARD_NAME);
+
+		if (board_name && board_vendor &&
+		    !strcmp(board_vendor, "ASRock")) {
+			/*
+			 * Auxiliary fan monitoring is not enabled on ASRock
+			 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
+			 * Observed with BIOS version 2.00.
+			 */
+			if (!strcmp(board_name, "Z77 Pro4-M")) {
+				if ((data->sio_reg_enable & 0xe0) != 0xe0) {
+					data->sio_reg_enable |= 0xe0;
+					superio_outb(sioreg, SIO_REG_ENABLE,
+						     data->sio_reg_enable);
+				}
+			}
+		}
+
+		if (data->sio_reg_enable & 0x80)
+			fan3pin = gpok;
+		else
+			fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
+
+		if (data->sio_reg_enable & 0x40)
+			fan4pin = gpok;
+		else
+			fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
+
+		if (data->sio_reg_enable & 0x20)
+			fan5pin = gpok;
+		else
+			fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
+
+		fan4min = fan4pin;
+		fan6pin = false;
+		pwm3pin = fan3pin;
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
+	} else if (data->kind == nct6106) {
+		regval = superio_inb(sioreg, 0x24);
+		fan3pin = !(regval & 0x80);
+		pwm3pin = regval & 0x08;
+
+		fan4pin = false;
+		fan4min = false;
+		fan5pin = false;
+		fan6pin = false;
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
+	} else {	/* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
+		regval = superio_inb(sioreg, 0x1c);
+
+		fan3pin = !(regval & (1 << 5));
+		fan4pin = !(regval & (1 << 6));
+		fan5pin = !(regval & (1 << 7));
+
+		pwm3pin = !(regval & (1 << 0));
+		pwm4pin = !(regval & (1 << 1));
+		pwm5pin = !(regval & (1 << 2));
+
+		fan4min = fan4pin;
+
+		if (data->kind == nct6791 || data->kind == nct6792 ||
+		    data->kind == nct6793) {
+			regval = superio_inb(sioreg, 0x2d);
+			fan6pin = (regval & (1 << 1));
+			pwm6pin = (regval & (1 << 0));
+		} else {	/* NCT6779D */
+			fan6pin = false;
+			pwm6pin = false;
+		}
+	}
+
+	/* fan 1 and 2 (0x03) are always present */
+	data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
+		(fan5pin << 4) | (fan6pin << 5);
+	data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
+		(fan5pin << 4);
+	data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
+		(pwm5pin << 4) | (pwm6pin << 5);
+}
+
+static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
+			     int *available, int *mask)
+{
+	int i;
+	u8 src;
+
+	for (i = 0; i < data->pwm_num && *available; i++) {
+		int index;
+
+		if (!regp[i])
+			continue;
+		src = nct6775_read_value(data, regp[i]);
+		src &= 0x1f;
+		if (!src || (*mask & (1 << src)))
+			continue;
+		if (src >= data->temp_label_num ||
+		    !strlen(data->temp_label[src]))
+			continue;
+
+		index = __ffs(*available);
+		nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
+		*available &= ~(1 << index);
+		*mask |= 1 << src;
+	}
+}
+
+static int nct6775_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
+	struct nct6775_data *data;
+	struct resource *res;
+	int i, s, err = 0;
+	int src, mask, available;
+	const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
+	const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
+	const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
+	int num_reg_temp, num_reg_temp_mon;
+	u8 cr2a;
+	struct attribute_group *group;
+	struct device *hwmon_dev;
+	int num_attr_groups = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
+				 DRVNAME))
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->kind = sio_data->kind;
+	data->sioreg = sio_data->sioreg;
+	data->addr = res->start;
+	mutex_init(&data->update_lock);
+	data->name = nct6775_device_names[data->kind];
+	data->bank = 0xff;		/* Force initial bank selection */
+	platform_set_drvdata(pdev, data);
+
+	switch (data->kind) {
+	case nct6106:
+		data->in_num = 9;
+		data->pwm_num = 3;
+		data->auto_pwm_num = 4;
+		data->temp_fixed_num = 3;
+		data->num_temp_alarms = 6;
+		data->num_temp_beeps = 6;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+
+		data->temp_label = nct6776_temp_label;
+		data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+		data->REG_VBAT = NCT6106_REG_VBAT;
+		data->REG_DIODE = NCT6106_REG_DIODE;
+		data->DIODE_MASK = NCT6106_DIODE_MASK;
+		data->REG_VIN = NCT6106_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+		data->REG_TARGET = NCT6106_REG_TARGET;
+		data->REG_FAN = NCT6106_REG_FAN;
+		data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+		data->REG_PWM[0] = NCT6106_REG_PWM;
+		data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6106_REG_ALARM;
+		data->ALARM_BITS = NCT6106_ALARM_BITS;
+		data->REG_BEEP = NCT6106_REG_BEEP;
+		data->BEEP_BITS = NCT6106_BEEP_BITS;
+
+		reg_temp = NCT6106_REG_TEMP;
+		reg_temp_mon = NCT6106_REG_TEMP_MON;
+		num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+		num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
+		reg_temp_over = NCT6106_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
+		break;
+	case nct6775:
+		data->in_num = 9;
+		data->pwm_num = 3;
+		data->auto_pwm_num = 6;
+		data->has_fan_div = true;
+		data->temp_fixed_num = 3;
+		data->num_temp_alarms = 3;
+		data->num_temp_beeps = 3;
+
+		data->ALARM_BITS = NCT6775_ALARM_BITS;
+		data->BEEP_BITS = NCT6775_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg16;
+		data->fan_from_reg_min = fan_from_reg8;
+		data->target_temp_mask = 0x7f;
+		data->tolerance_mask = 0x0f;
+		data->speed_tolerance_limit = 15;
+
+		data->temp_label = nct6775_temp_label;
+		data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
+
+		data->REG_CONFIG = NCT6775_REG_CONFIG;
+		data->REG_VBAT = NCT6775_REG_VBAT;
+		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
+		data->REG_VIN = NCT6775_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6775_REG_FAN;
+		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+		data->REG_PWM[0] = NCT6775_REG_PWM;
+		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
+		data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
+		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6775_REG_ALARM;
+		data->REG_BEEP = NCT6775_REG_BEEP;
+
+		reg_temp = NCT6775_REG_TEMP;
+		reg_temp_mon = NCT6775_REG_TEMP_MON;
+		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+		num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
+		reg_temp_over = NCT6775_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+		reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6775_REG_TEMP_CRIT;
+
+		break;
+	case nct6776:
+		data->in_num = 9;
+		data->pwm_num = 3;
+		data->auto_pwm_num = 4;
+		data->has_fan_div = false;
+		data->temp_fixed_num = 3;
+		data->num_temp_alarms = 3;
+		data->num_temp_beeps = 6;
+
+		data->ALARM_BITS = NCT6776_ALARM_BITS;
+		data->BEEP_BITS = NCT6776_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->target_temp_mask = 0xff;
+		data->tolerance_mask = 0x07;
+		data->speed_tolerance_limit = 63;
+
+		data->temp_label = nct6776_temp_label;
+		data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+		data->REG_CONFIG = NCT6775_REG_CONFIG;
+		data->REG_VBAT = NCT6775_REG_VBAT;
+		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
+		data->REG_VIN = NCT6775_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6775_REG_FAN;
+		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+		data->REG_PWM[0] = NCT6775_REG_PWM;
+		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6775_REG_ALARM;
+		data->REG_BEEP = NCT6776_REG_BEEP;
+
+		reg_temp = NCT6775_REG_TEMP;
+		reg_temp_mon = NCT6775_REG_TEMP_MON;
+		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+		num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
+		reg_temp_over = NCT6775_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+		reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6776_REG_TEMP_CRIT;
+
+		break;
+	case nct6779:
+		data->in_num = 15;
+		data->pwm_num = 5;
+		data->auto_pwm_num = 4;
+		data->has_fan_div = false;
+		data->temp_fixed_num = 6;
+		data->num_temp_alarms = 2;
+		data->num_temp_beeps = 2;
+
+		data->ALARM_BITS = NCT6779_ALARM_BITS;
+		data->BEEP_BITS = NCT6779_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->target_temp_mask = 0xff;
+		data->tolerance_mask = 0x07;
+		data->speed_tolerance_limit = 63;
+
+		data->temp_label = nct6779_temp_label;
+		data->temp_label_num = NCT6779_NUM_LABELS;
+
+		data->REG_CONFIG = NCT6775_REG_CONFIG;
+		data->REG_VBAT = NCT6775_REG_VBAT;
+		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
+		data->REG_VIN = NCT6779_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6779_REG_FAN;
+		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+		data->REG_PWM[0] = NCT6775_REG_PWM;
+		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6779_REG_ALARM;
+		data->REG_BEEP = NCT6776_REG_BEEP;
+
+		reg_temp = NCT6779_REG_TEMP;
+		reg_temp_mon = NCT6779_REG_TEMP_MON;
+		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+		num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
+		reg_temp_over = NCT6779_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+		reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+		break;
+	case nct6791:
+	case nct6792:
+	case nct6793:
+		data->in_num = 15;
+		data->pwm_num = 6;
+		data->auto_pwm_num = 4;
+		data->has_fan_div = false;
+		data->temp_fixed_num = 6;
+		data->num_temp_alarms = 2;
+		data->num_temp_beeps = 2;
+
+		data->ALARM_BITS = NCT6791_ALARM_BITS;
+		data->BEEP_BITS = NCT6779_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->target_temp_mask = 0xff;
+		data->tolerance_mask = 0x07;
+		data->speed_tolerance_limit = 63;
+
+		switch (data->kind) {
+		default:
+		case nct6791:
+			data->temp_label = nct6779_temp_label;
+			break;
+		case nct6792:
+			data->temp_label = nct6792_temp_label;
+			break;
+		case nct6793:
+			data->temp_label = nct6793_temp_label;
+			break;
+		}
+		data->temp_label_num = NCT6791_NUM_LABELS;
+
+		data->REG_CONFIG = NCT6775_REG_CONFIG;
+		data->REG_VBAT = NCT6775_REG_VBAT;
+		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
+		data->REG_VIN = NCT6779_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6779_REG_FAN;
+		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+		data->REG_PWM[0] = NCT6775_REG_PWM;
+		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6791_REG_ALARM;
+		if (data->kind == nct6791)
+			data->REG_BEEP = NCT6776_REG_BEEP;
+		else
+			data->REG_BEEP = NCT6792_REG_BEEP;
+
+		reg_temp = NCT6779_REG_TEMP;
+		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+		if (data->kind == nct6791) {
+			reg_temp_mon = NCT6779_REG_TEMP_MON;
+			num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
+		} else {
+			reg_temp_mon = NCT6792_REG_TEMP_MON;
+			num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
+		}
+		reg_temp_over = NCT6779_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+		reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+		break;
+	default:
+		return -ENODEV;
+	}
+	data->have_in = (1 << data->in_num) - 1;
+	data->have_temp = 0;
+
+	/*
+	 * On some boards, not all available temperature sources are monitored,
+	 * even though some of the monitoring registers are unused.
+	 * Get list of unused monitoring registers, then detect if any fan
+	 * controls are configured to use unmonitored temperature sources.
+	 * If so, assign the unmonitored temperature sources to available
+	 * monitoring registers.
+	 */
+	mask = 0;
+	available = 0;
+	for (i = 0; i < num_reg_temp; i++) {
+		if (reg_temp[i] == 0)
+			continue;
+
+		src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+		if (!src || (mask & (1 << src)))
+			available |= 1 << i;
+
+		mask |= 1 << src;
+	}
+
+	/*
+	 * Now find unmonitored temperature registers and enable monitoring
+	 * if additional monitoring registers are available.
+	 */
+	add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
+	add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
+
+	mask = 0;
+	s = NUM_TEMP_FIXED;	/* First dynamic temperature attribute */
+	for (i = 0; i < num_reg_temp; i++) {
+		if (reg_temp[i] == 0)
+			continue;
+
+		src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+		if (!src || (mask & (1 << src)))
+			continue;
+
+		if (src >= data->temp_label_num ||
+		    !strlen(data->temp_label[src])) {
+			dev_info(dev,
+				 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
+				 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
+			continue;
+		}
+
+		mask |= 1 << src;
+
+		/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+		if (src <= data->temp_fixed_num) {
+			data->have_temp |= 1 << (src - 1);
+			data->have_temp_fixed |= 1 << (src - 1);
+			data->reg_temp[0][src - 1] = reg_temp[i];
+			data->reg_temp[1][src - 1] = reg_temp_over[i];
+			data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+			if (reg_temp_crit_h && reg_temp_crit_h[i])
+				data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
+			else if (reg_temp_crit[src - 1])
+				data->reg_temp[3][src - 1]
+				  = reg_temp_crit[src - 1];
+			if (reg_temp_crit_l && reg_temp_crit_l[i])
+				data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
+			data->reg_temp_config[src - 1] = reg_temp_config[i];
+			data->temp_src[src - 1] = src;
+			continue;
+		}
+
+		if (s >= NUM_TEMP)
+			continue;
+
+		/* Use dynamic index for other sources */
+		data->have_temp |= 1 << s;
+		data->reg_temp[0][s] = reg_temp[i];
+		data->reg_temp[1][s] = reg_temp_over[i];
+		data->reg_temp[2][s] = reg_temp_hyst[i];
+		data->reg_temp_config[s] = reg_temp_config[i];
+		if (reg_temp_crit_h && reg_temp_crit_h[i])
+			data->reg_temp[3][s] = reg_temp_crit_h[i];
+		else if (reg_temp_crit[src - 1])
+			data->reg_temp[3][s] = reg_temp_crit[src - 1];
+		if (reg_temp_crit_l && reg_temp_crit_l[i])
+			data->reg_temp[4][s] = reg_temp_crit_l[i];
+
+		data->temp_src[s] = src;
+		s++;
+	}
+
+	/*
+	 * Repeat with temperatures used for fan control.
+	 * This set of registers does not support limits.
+	 */
+	for (i = 0; i < num_reg_temp_mon; i++) {
+		if (reg_temp_mon[i] == 0)
+			continue;
+
+		src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
+		if (!src || (mask & (1 << src)))
+			continue;
+
+		if (src >= data->temp_label_num ||
+		    !strlen(data->temp_label[src])) {
+			dev_info(dev,
+				 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
+				 src, i, data->REG_TEMP_SEL[i],
+				 reg_temp_mon[i]);
+			continue;
+		}
+
+		mask |= 1 << src;
+
+		/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+		if (src <= data->temp_fixed_num) {
+			if (data->have_temp & (1 << (src - 1)))
+				continue;
+			data->have_temp |= 1 << (src - 1);
+			data->have_temp_fixed |= 1 << (src - 1);
+			data->reg_temp[0][src - 1] = reg_temp_mon[i];
+			data->temp_src[src - 1] = src;
+			continue;
+		}
+
+		if (s >= NUM_TEMP)
+			continue;
+
+		/* Use dynamic index for other sources */
+		data->have_temp |= 1 << s;
+		data->reg_temp[0][s] = reg_temp_mon[i];
+		data->temp_src[s] = src;
+		s++;
+	}
+
+#ifdef USE_ALTERNATE
+	/*
+	 * Go through the list of alternate temp registers and enable
+	 * if possible.
+	 * The temperature is already monitored if the respective bit in <mask>
+	 * is set.
+	 */
+	for (i = 0; i < data->temp_label_num - 1; i++) {
+		if (!reg_temp_alternate[i])
+			continue;
+		if (mask & (1 << (i + 1)))
+			continue;
+		if (i < data->temp_fixed_num) {
+			if (data->have_temp & (1 << i))
+				continue;
+			data->have_temp |= 1 << i;
+			data->have_temp_fixed |= 1 << i;
+			data->reg_temp[0][i] = reg_temp_alternate[i];
+			if (i < num_reg_temp) {
+				data->reg_temp[1][i] = reg_temp_over[i];
+				data->reg_temp[2][i] = reg_temp_hyst[i];
+			}
+			data->temp_src[i] = i + 1;
+			continue;
+		}
+
+		if (s >= NUM_TEMP)	/* Abort if no more space */
+			break;
+
+		data->have_temp |= 1 << s;
+		data->reg_temp[0][s] = reg_temp_alternate[i];
+		data->temp_src[s] = i + 1;
+		s++;
+	}
+#endif /* USE_ALTERNATE */
+
+	/* Initialize the chip */
+	nct6775_init_device(data);
+
+	err = superio_enter(sio_data->sioreg);
+	if (err)
+		return err;
+
+	cr2a = superio_inb(sio_data->sioreg, 0x2a);
+	switch (data->kind) {
+	case nct6775:
+		data->have_vid = (cr2a & 0x40);
+		break;
+	case nct6776:
+		data->have_vid = (cr2a & 0x60) == 0x40;
+		break;
+	case nct6106:
+	case nct6779:
+	case nct6791:
+	case nct6792:
+	case nct6793:
+		break;
+	}
+
+	/*
+	 * Read VID value
+	 * We can get the VID input values directly at logical device D 0xe3.
+	 */
+	if (data->have_vid) {
+		superio_select(sio_data->sioreg, NCT6775_LD_VID);
+		data->vid = superio_inb(sio_data->sioreg, 0xe3);
+		data->vrm = vid_which_vrm();
+	}
+
+	if (fan_debounce) {
+		u8 tmp;
+
+		superio_select(sio_data->sioreg, NCT6775_LD_HWM);
+		tmp = superio_inb(sio_data->sioreg,
+				  NCT6775_REG_CR_FAN_DEBOUNCE);
+		switch (data->kind) {
+		case nct6106:
+			tmp |= 0xe0;
+			break;
+		case nct6775:
+			tmp |= 0x1e;
+			break;
+		case nct6776:
+		case nct6779:
+			tmp |= 0x3e;
+			break;
+		case nct6791:
+		case nct6792:
+		case nct6793:
+			tmp |= 0x7e;
+			break;
+		}
+		superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
+			     tmp);
+		dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
+			 data->name);
+	}
+
+	nct6775_check_fan_inputs(data);
+
+	superio_exit(sio_data->sioreg);
+
+	/* Read fan clock dividers immediately */
+	nct6775_init_fan_common(dev, data);
+
+	/* Register sysfs hooks */
+	group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
+					  data->pwm_num);
+	if (IS_ERR(group))
+		return PTR_ERR(group);
+
+	data->groups[num_attr_groups++] = group;
+
+	group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
+					  fls(data->have_in));
+	if (IS_ERR(group))
+		return PTR_ERR(group);
+
+	data->groups[num_attr_groups++] = group;
+
+	group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
+					  fls(data->has_fan));
+	if (IS_ERR(group))
+		return PTR_ERR(group);
+
+	data->groups[num_attr_groups++] = group;
+
+	group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
+					  fls(data->have_temp));
+	if (IS_ERR(group))
+		return PTR_ERR(group);
+
+	data->groups[num_attr_groups++] = group;
+	data->groups[num_attr_groups++] = &nct6775_group_other;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static void nct6791_enable_io_mapping(int sioaddr)
+{
+	int val;
+
+	val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
+	if (val & 0x10) {
+		pr_info("Enabling hardware monitor logical device mappings.\n");
+		superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
+			     val & ~0x10);
+	}
+}
+
+static int __maybe_unused nct6775_suspend(struct device *dev)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+
+	mutex_lock(&data->update_lock);
+	data->vbat = nct6775_read_value(data, data->REG_VBAT);
+	if (data->kind == nct6775) {
+		data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+		data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static int __maybe_unused nct6775_resume(struct device *dev)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int sioreg = data->sioreg;
+	int i, j, err = 0;
+	u8 reg;
+
+	mutex_lock(&data->update_lock);
+	data->bank = 0xff;		/* Force initial bank selection */
+
+	err = superio_enter(sioreg);
+	if (err)
+		goto abort;
+
+	superio_select(sioreg, NCT6775_LD_HWM);
+	reg = superio_inb(sioreg, SIO_REG_ENABLE);
+	if (reg != data->sio_reg_enable)
+		superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
+
+	if (data->kind == nct6791 || data->kind == nct6792 ||
+	    data->kind == nct6793)
+		nct6791_enable_io_mapping(sioreg);
+
+	superio_exit(sioreg);
+
+	/* Restore limits */
+	for (i = 0; i < data->in_num; i++) {
+		if (!(data->have_in & (1 << i)))
+			continue;
+
+		nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
+				    data->in[i][1]);
+		nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
+				    data->in[i][2]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+		if (!(data->has_fan_min & (1 << i)))
+			continue;
+
+		nct6775_write_value(data, data->REG_FAN_MIN[i],
+				    data->fan_min[i]);
+	}
+
+	for (i = 0; i < NUM_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+
+		for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
+			if (data->reg_temp[j][i])
+				nct6775_write_temp(data, data->reg_temp[j][i],
+						   data->temp[j][i]);
+	}
+
+	/* Restore other settings */
+	nct6775_write_value(data, data->REG_VBAT, data->vbat);
+	if (data->kind == nct6775) {
+		nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
+		nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
+	}
+
+abort:
+	/* Force re-reading all values */
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+
+	return err;
+}
+
+static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
+
+static struct platform_driver nct6775_driver = {
+	.driver = {
+		.name	= DRVNAME,
+		.pm	= &nct6775_dev_pm_ops,
+	},
+	.probe		= nct6775_probe,
+};
+
+/* nct6775_find() looks for a '627 in the Super-I/O config space */
+static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
+{
+	u16 val;
+	int err;
+	int addr;
+
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
+
+	if (force_id)
+		val = force_id;
+	else
+		val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+		    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+	switch (val & SIO_ID_MASK) {
+	case SIO_NCT6106_ID:
+		sio_data->kind = nct6106;
+		break;
+	case SIO_NCT6775_ID:
+		sio_data->kind = nct6775;
+		break;
+	case SIO_NCT6776_ID:
+		sio_data->kind = nct6776;
+		break;
+	case SIO_NCT6779_ID:
+		sio_data->kind = nct6779;
+		break;
+	case SIO_NCT6791_ID:
+		sio_data->kind = nct6791;
+		break;
+	case SIO_NCT6792_ID:
+		sio_data->kind = nct6792;
+		break;
+	case SIO_NCT6793_ID:
+		sio_data->kind = nct6793;
+		break;
+	default:
+		if (val != 0xffff)
+			pr_debug("unsupported chip ID: 0x%04x\n", val);
+		superio_exit(sioaddr);
+		return -ENODEV;
+	}
+
+	/* We have a known chip, find the HWM I/O address */
+	superio_select(sioaddr, NCT6775_LD_HWM);
+	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+	addr = val & IOREGION_ALIGNMENT;
+	if (addr == 0) {
+		pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
+		superio_exit(sioaddr);
+		return -ENODEV;
+	}
+
+	/* Activate logical device if needed */
+	val = superio_inb(sioaddr, SIO_REG_ENABLE);
+	if (!(val & 0x01)) {
+		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+	}
+
+	if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
+	    sio_data->kind == nct6793)
+		nct6791_enable_io_mapping(sioaddr);
+
+	superio_exit(sioaddr);
+	pr_info("Found %s or compatible chip at %#x:%#x\n",
+		nct6775_sio_names[sio_data->kind], sioaddr, addr);
+	sio_data->sioreg = sioaddr;
+
+	return addr;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the nct6775 driver. But since we use platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev[2];
+
+static int __init sensors_nct6775_init(void)
+{
+	int i, err;
+	bool found = false;
+	int address;
+	struct resource res;
+	struct nct6775_sio_data sio_data;
+	int sioaddr[2] = { 0x2e, 0x4e };
+
+	err = platform_driver_register(&nct6775_driver);
+	if (err)
+		return err;
+
+	/*
+	 * initialize sio_data->kind and sio_data->sioreg.
+	 *
+	 * when Super-I/O functions move to a separate file, the Super-I/O
+	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+	 * nct6775 hardware monitor, and call probe()
+	 */
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		address = nct6775_find(sioaddr[i], &sio_data);
+		if (address <= 0)
+			continue;
+
+		found = true;
+
+		pdev[i] = platform_device_alloc(DRVNAME, address);
+		if (!pdev[i]) {
+			err = -ENOMEM;
+			goto exit_device_unregister;
+		}
+
+		err = platform_device_add_data(pdev[i], &sio_data,
+					       sizeof(struct nct6775_sio_data));
+		if (err)
+			goto exit_device_put;
+
+		memset(&res, 0, sizeof(res));
+		res.name = DRVNAME;
+		res.start = address + IOREGION_OFFSET;
+		res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+		res.flags = IORESOURCE_IO;
+
+		err = acpi_check_resource_conflict(&res);
+		if (err) {
+			platform_device_put(pdev[i]);
+			pdev[i] = NULL;
+			continue;
+		}
+
+		err = platform_device_add_resources(pdev[i], &res, 1);
+		if (err)
+			goto exit_device_put;
+
+		/* platform_device_add calls probe() */
+		err = platform_device_add(pdev[i]);
+		if (err)
+			goto exit_device_put;
+	}
+	if (!found) {
+		err = -ENODEV;
+		goto exit_unregister;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev[i]);
+exit_device_unregister:
+	while (--i >= 0) {
+		if (pdev[i])
+			platform_device_unregister(pdev[i]);
+	}
+exit_unregister:
+	platform_driver_unregister(&nct6775_driver);
+	return err;
+}
+
+static void __exit sensors_nct6775_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		if (pdev[i])
+			platform_device_unregister(pdev[i]);
+	}
+	platform_driver_unregister(&nct6775_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6775_init);
+module_exit(sensors_nct6775_exit);
diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c
new file mode 100644
index 0000000..12b94b0
--- /dev/null
+++ b/drivers/hwmon/nct7802.c
@@ -0,0 +1,1153 @@
+/*
+ * nct7802 - Driver for Nuvoton NCT7802Y
+ *
+ * Copyright (C) 2014  Guenter Roeck <linux@roeck-us.net>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define DRVNAME "nct7802"
+
+static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e };
+
+static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = {
+	{ 0x40, 0x00, 0x42, 0x44, 0x46 },
+	{ 0x3f, 0x00, 0x41, 0x43, 0x45 },
+};
+
+static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 };
+
+static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
+	{ 0, 0, 4, 0, 4 },
+	{ 2, 0, 6, 2, 6 },
+};
+
+#define REG_BANK		0x00
+#define REG_TEMP_LSB		0x05
+#define REG_TEMP_PECI_LSB	0x08
+#define REG_VOLTAGE_LOW		0x0f
+#define REG_FANCOUNT_LOW	0x13
+#define REG_START		0x21
+#define REG_MODE		0x22 /* 7.2.32 Mode Selection Register */
+#define REG_PECI_ENABLE		0x23
+#define REG_FAN_ENABLE		0x24
+#define REG_VMON_ENABLE		0x25
+#define REG_PWM(x)		(0x60 + (x))
+#define REG_SMARTFAN_EN(x)      (0x64 + (x) / 2)
+#define SMARTFAN_EN_SHIFT(x)    ((x) % 2 * 4)
+#define REG_VENDOR_ID		0xfd
+#define REG_CHIP_ID		0xfe
+#define REG_VERSION_ID		0xff
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct nct7802_data {
+	struct regmap *regmap;
+	struct mutex access_lock; /* for multi-byte read and write operations */
+};
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	unsigned int mode;
+	int ret;
+
+	ret = regmap_read(data->regmap, REG_MODE, &mode);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%u\n", (mode >> (2 * sattr->index) & 3) + 2);
+}
+
+static ssize_t store_temp_type(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	unsigned int type;
+	int err;
+
+	err = kstrtouint(buf, 0, &type);
+	if (err < 0)
+		return err;
+	if (sattr->index == 2 && type != 4) /* RD3 */
+		return -EINVAL;
+	if (type < 3 || type > 4)
+		return -EINVAL;
+	err = regmap_update_bits(data->regmap, REG_MODE,
+			3 << 2 * sattr->index, (type - 2) << 2 * sattr->index);
+	return err ? : count;
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned int regval;
+	int ret;
+
+	if (sattr->index > 1)
+		return sprintf(buf, "1\n");
+
+	ret = regmap_read(data->regmap, 0x5E, &regval);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%u\n", !(regval & (1 << sattr->index)));
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	if (!attr->index)
+		return sprintf(buf, "255\n");
+
+	ret = regmap_read(data->regmap, attr->index, &val);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int err;
+	u8 val;
+
+	err = kstrtou8(buf, 0, &val);
+	if (err < 0)
+		return err;
+
+	err = regmap_write(data->regmap, attr->index, val);
+	return err ? : count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	unsigned int reg, enabled;
+	int ret;
+
+	ret = regmap_read(data->regmap, REG_SMARTFAN_EN(sattr->index), &reg);
+	if (ret < 0)
+		return ret;
+	enabled = reg >> SMARTFAN_EN_SHIFT(sattr->index) & 1;
+	return sprintf(buf, "%u\n", enabled + 1);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	u8 val;
+	int ret;
+
+	ret = kstrtou8(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	if (val < 1 || val > 2)
+		return -EINVAL;
+	ret = regmap_update_bits(data->regmap, REG_SMARTFAN_EN(sattr->index),
+				 1 << SMARTFAN_EN_SHIFT(sattr->index),
+				 (val - 1) << SMARTFAN_EN_SHIFT(sattr->index));
+	return ret ? : count;
+}
+
+static int nct7802_read_temp(struct nct7802_data *data,
+			     u8 reg_temp, u8 reg_temp_low, int *temp)
+{
+	unsigned int t1, t2 = 0;
+	int err;
+
+	*temp = 0;
+
+	mutex_lock(&data->access_lock);
+	err = regmap_read(data->regmap, reg_temp, &t1);
+	if (err < 0)
+		goto abort;
+	t1 <<= 8;
+	if (reg_temp_low) {	/* 11 bit data */
+		err = regmap_read(data->regmap, reg_temp_low, &t2);
+		if (err < 0)
+			goto abort;
+	}
+	t1 |= t2 & 0xe0;
+	*temp = (s16)t1 / 32 * 125;
+abort:
+	mutex_unlock(&data->access_lock);
+	return err;
+}
+
+static int nct7802_read_fan(struct nct7802_data *data, u8 reg_fan)
+{
+	unsigned int f1, f2;
+	int ret;
+
+	mutex_lock(&data->access_lock);
+	ret = regmap_read(data->regmap, reg_fan, &f1);
+	if (ret < 0)
+		goto abort;
+	ret = regmap_read(data->regmap, REG_FANCOUNT_LOW, &f2);
+	if (ret < 0)
+		goto abort;
+	ret = (f1 << 5) | (f2 >> 3);
+	/* convert fan count to rpm */
+	if (ret == 0x1fff)	/* maximum value, assume fan is stopped */
+		ret = 0;
+	else if (ret)
+		ret = DIV_ROUND_CLOSEST(1350000U, ret);
+abort:
+	mutex_unlock(&data->access_lock);
+	return ret;
+}
+
+static int nct7802_read_fan_min(struct nct7802_data *data, u8 reg_fan_low,
+				u8 reg_fan_high)
+{
+	unsigned int f1, f2;
+	int ret;
+
+	mutex_lock(&data->access_lock);
+	ret = regmap_read(data->regmap, reg_fan_low, &f1);
+	if (ret < 0)
+		goto abort;
+	ret = regmap_read(data->regmap, reg_fan_high, &f2);
+	if (ret < 0)
+		goto abort;
+	ret = f1 | ((f2 & 0xf8) << 5);
+	/* convert fan count to rpm */
+	if (ret == 0x1fff)	/* maximum value, assume no limit */
+		ret = 0;
+	else if (ret)
+		ret = DIV_ROUND_CLOSEST(1350000U, ret);
+	else
+		ret = 1350000U;
+abort:
+	mutex_unlock(&data->access_lock);
+	return ret;
+}
+
+static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low,
+				 u8 reg_fan_high, unsigned long limit)
+{
+	int err;
+
+	if (limit)
+		limit = DIV_ROUND_CLOSEST(1350000U, limit);
+	else
+		limit = 0x1fff;
+	limit = clamp_val(limit, 0, 0x1fff);
+
+	mutex_lock(&data->access_lock);
+	err = regmap_write(data->regmap, reg_fan_low, limit & 0xff);
+	if (err < 0)
+		goto abort;
+
+	err = regmap_write(data->regmap, reg_fan_high, (limit & 0x1f00) >> 5);
+abort:
+	mutex_unlock(&data->access_lock);
+	return err;
+}
+
+static u8 nct7802_vmul[] = { 4, 2, 2, 2, 2 };
+
+static int nct7802_read_voltage(struct nct7802_data *data, int nr, int index)
+{
+	unsigned int v1, v2;
+	int ret;
+
+	mutex_lock(&data->access_lock);
+	if (index == 0) {	/* voltage */
+		ret = regmap_read(data->regmap, REG_VOLTAGE[nr], &v1);
+		if (ret < 0)
+			goto abort;
+		ret = regmap_read(data->regmap, REG_VOLTAGE_LOW, &v2);
+		if (ret < 0)
+			goto abort;
+		ret = ((v1 << 2) | (v2 >> 6)) * nct7802_vmul[nr];
+	}  else {	/* limit */
+		int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
+
+		ret = regmap_read(data->regmap,
+				  REG_VOLTAGE_LIMIT_LSB[index - 1][nr], &v1);
+		if (ret < 0)
+			goto abort;
+		ret = regmap_read(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
+				  &v2);
+		if (ret < 0)
+			goto abort;
+		ret = (v1 | ((v2 << shift) & 0x300)) * nct7802_vmul[nr];
+	}
+abort:
+	mutex_unlock(&data->access_lock);
+	return ret;
+}
+
+static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index,
+				 unsigned long voltage)
+{
+	int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
+	int err;
+
+	voltage = clamp_val(voltage, 0, 0x3ff * nct7802_vmul[nr]);
+	voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]);
+
+	mutex_lock(&data->access_lock);
+	err = regmap_write(data->regmap,
+			   REG_VOLTAGE_LIMIT_LSB[index - 1][nr],
+			   voltage & 0xff);
+	if (err < 0)
+		goto abort;
+
+	err = regmap_update_bits(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
+				 0x0300 >> shift, (voltage & 0x0300) >> shift);
+abort:
+	mutex_unlock(&data->access_lock);
+	return err;
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int voltage;
+
+	voltage = nct7802_read_voltage(data, sattr->nr, sattr->index);
+	if (voltage < 0)
+		return voltage;
+
+	return sprintf(buf, "%d\n", voltage);
+}
+
+static ssize_t store_in(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int index = sattr->index;
+	int nr = sattr->nr;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	err = nct7802_write_voltage(data, nr, index, val);
+	return err ? : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int err, temp;
+
+	err = nct7802_read_temp(data, sattr->nr, sattr->index, &temp);
+	if (err < 0)
+		return err;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t store_temp(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int nr = sattr->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
+
+	err = regmap_write(data->regmap, nr, val & 0xff);
+	return err ? : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int speed;
+
+	speed = nct7802_read_fan(data, sattr->index);
+	if (speed < 0)
+		return speed;
+
+	return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int speed;
+
+	speed = nct7802_read_fan_min(data, sattr->nr, sattr->index);
+	if (speed < 0)
+		return speed;
+
+	return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	err = nct7802_write_fan_min(data, sattr->nr, sattr->index, val);
+	return err ? : count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	int bit = sattr->index;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(data->regmap, sattr->nr, &val);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%u\n", !!(val & (1 << bit)));
+}
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned int regval;
+	int err;
+
+	err = regmap_read(data->regmap, sattr->nr, &regval);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%u\n", !!(regval & (1 << sattr->index)));
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+	   size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 1)
+		return -EINVAL;
+
+	err = regmap_update_bits(data->regmap, sattr->nr, 1 << sattr->index,
+				 val ? 1 << sattr->index : 0);
+	return err ? : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
+			  show_temp_type, store_temp_type, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01,
+			    REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x31, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x30, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x3a, 0);
+
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
+			  show_temp_type, store_temp_type, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02,
+			    REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x33, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x32, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x3b, 0);
+
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
+			  show_temp_type, store_temp_type, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03,
+			    REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x35, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x34, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x3c, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 0x04, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x37, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x36, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x3d, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 0x06,
+			    REG_TEMP_PECI_LSB);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x39, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x38, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp,
+			    store_temp, 0x3e, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 0x07,
+			    REG_TEMP_PECI_LSB);
+
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+			    0x18, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_alarm, NULL,
+			    0x18, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_alarm, NULL,
+			    0x18, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_alarm, NULL,
+			    0x18, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_min_alarm, S_IRUGO, show_alarm, NULL,
+			    0x18, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+			    0x19, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
+			    0x19, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
+			    0x19, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
+			    0x19, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
+			    0x19, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+			    0x1b, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+			    0x1b, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
+			    0x1b, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_alarm, NULL,
+			    0x1b, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_crit_alarm, S_IRUGO, show_alarm, NULL,
+			    0x1b, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_alarm, NULL, 0x17, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_alarm, NULL, 0x17, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_alarm, NULL, 0x17, 2);
+
+static SENSOR_DEVICE_ATTR_2(temp1_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 4);
+static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep,
+			    store_beep, 0x5c, 5);
+
+static struct attribute *nct7802_temp_attrs[] = {
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_type.dev_attr.attr,		/* 10 */
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_type.dev_attr.attr,		/* 20 */
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp4_input.dev_attr.attr,		/* 30 */
+	&sensor_dev_attr_temp4_min.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit.dev_attr.attr,
+	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp4_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp5_input.dev_attr.attr,		/* 38 */
+	&sensor_dev_attr_temp5_min.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit.dev_attr.attr,
+	&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_beep.dev_attr.attr,
+
+	&sensor_dev_attr_temp6_input.dev_attr.attr,		/* 46 */
+	&sensor_dev_attr_temp6_beep.dev_attr.attr,
+
+	NULL
+};
+
+static umode_t nct7802_temp_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned int reg;
+	int err;
+
+	err = regmap_read(data->regmap, REG_MODE, &reg);
+	if (err < 0)
+		return 0;
+
+	if (index < 10 &&
+	    (reg & 03) != 0x01 && (reg & 0x03) != 0x02)		/* RD1 */
+		return 0;
+
+	if (index >= 10 && index < 20 &&
+	    (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08)	/* RD2 */
+		return 0;
+	if (index >= 20 && index < 30 && (reg & 0x30) != 0x20)	/* RD3 */
+		return 0;
+
+	if (index >= 30 && index < 38)				/* local */
+		return attr->mode;
+
+	err = regmap_read(data->regmap, REG_PECI_ENABLE, &reg);
+	if (err < 0)
+		return 0;
+
+	if (index >= 38 && index < 46 && !(reg & 0x01))		/* PECI 0 */
+		return 0;
+
+	if (index >= 0x46 && (!(reg & 0x02)))			/* PECI 1 */
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute_group nct7802_temp_group = {
+	.attrs = nct7802_temp_attrs,
+	.is_visible = nct7802_temp_is_visible,
+};
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, store_in,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, store_in,
+			    0, 2);
+static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 3);
+static SENSOR_DEVICE_ATTR_2(in0_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5a, 3);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, store_in,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, store_in,
+			    2, 2);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 0);
+static SENSOR_DEVICE_ATTR_2(in2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5a, 0);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, store_in,
+			    3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, store_in,
+			    3, 2);
+static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 1);
+static SENSOR_DEVICE_ATTR_2(in3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5a, 1);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, store_in,
+			    4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, store_in,
+			    4, 2);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 2);
+static SENSOR_DEVICE_ATTR_2(in4_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5a, 2);
+
+static struct attribute *nct7802_in_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_beep.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,	/* 5 */
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,	/* 6 */
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_beep.dev_attr.attr,
+
+	&sensor_dev_attr_in3_input.dev_attr.attr,	/* 11 */
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_beep.dev_attr.attr,
+
+	&sensor_dev_attr_in4_input.dev_attr.attr,	/* 17 */
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_beep.dev_attr.attr,
+
+	NULL,
+};
+
+static umode_t nct7802_in_is_visible(struct kobject *kobj,
+				     struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	unsigned int reg;
+	int err;
+
+	if (index < 6)						/* VCC, VCORE */
+		return attr->mode;
+
+	err = regmap_read(data->regmap, REG_MODE, &reg);
+	if (err < 0)
+		return 0;
+
+	if (index >= 6 && index < 11 && (reg & 0x03) != 0x03)	/* VSEN1 */
+		return 0;
+	if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c)	/* VSEN2 */
+		return 0;
+	if (index >= 17 && (reg & 0x30) != 0x30)		/* VSEN3 */
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute_group nct7802_in_group = {
+	.attrs = nct7802_in_attrs,
+	.is_visible = nct7802_in_is_visible,
+};
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0x10);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan_min,
+			    store_fan_min, 0x49, 0x4c);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5b, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 0x11);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan_min,
+			    store_fan_min, 0x4a, 0x4d);
+static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5b, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 0x12);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan_min,
+			    store_fan_min, 0x4b, 0x4e);
+static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+			    0x5b, 2);
+
+/* 7.2.89 Fan Control Output Type */
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
+
+/* 7.2.91... Fan Control Output Value */
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm,
+			  REG_PWM(0));
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm,
+			  REG_PWM(1));
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm,
+			  REG_PWM(2));
+
+/* 7.2.95... Temperature to Fan mapping Relationships Register */
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+			  store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+			  store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+			  store_pwm_enable, 2);
+
+static struct attribute *nct7802_fan_attrs[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan1_beep.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_beep.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_beep.dev_attr.attr,
+
+	NULL
+};
+
+static umode_t nct7802_fan_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int fan = index / 4;	/* 4 attributes per fan */
+	unsigned int reg;
+	int err;
+
+	err = regmap_read(data->regmap, REG_FAN_ENABLE, &reg);
+	if (err < 0 || !(reg & (1 << fan)))
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute_group nct7802_fan_group = {
+	.attrs = nct7802_fan_attrs,
+	.is_visible = nct7802_fan_is_visible,
+};
+
+static struct attribute *nct7802_pwm_attrs[] = {
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group nct7802_pwm_group = {
+	.attrs = nct7802_pwm_attrs,
+};
+
+/* 7.2.115... 0x80-0x83, 0x84 Temperature (X-axis) transition */
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x80, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x81, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x82, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x83, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point5_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x84, 0);
+
+/* 7.2.120... 0x85-0x88 PWM (Y-axis) transition */
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x85);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x86);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x87);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x88);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0);
+
+/* 7.2.124 Table 2 X-axis Transition Point 1 Register */
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x90, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x91, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x92, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x93, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point5_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0x94, 0);
+
+/* 7.2.129 Table 2 Y-axis Transition Point 1 Register */
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x95);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x96);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x97);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0x98);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0);
+
+/* 7.2.133 Table 3 X-axis Transition Point 1 Register */
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0xA0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0xA1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0xA2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0xA3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point5_temp, S_IRUGO | S_IWUSR,
+			    show_temp, store_temp, 0xA4, 0);
+
+/* 7.2.138 Table 3 Y-axis Transition Point 1 Register */
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0xA5);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0xA6);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0xA7);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, S_IRUGO | S_IWUSR,
+			  show_pwm, store_pwm, 0xA8);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0);
+
+static struct attribute *nct7802_auto_point_attrs[] = {
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr,
+
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr,
+
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr,
+
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr,
+
+	NULL
+};
+
+static struct attribute_group nct7802_auto_point_group = {
+	.attrs = nct7802_auto_point_attrs,
+};
+
+static const struct attribute_group *nct7802_groups[] = {
+	&nct7802_temp_group,
+	&nct7802_in_group,
+	&nct7802_fan_group,
+	&nct7802_pwm_group,
+	&nct7802_auto_point_group,
+	NULL
+};
+
+static int nct7802_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	int reg;
+
+	/*
+	 * Chip identification registers are only available in bank 0,
+	 * so only attempt chip detection if bank 0 is selected
+	 */
+	reg = i2c_smbus_read_byte_data(client, REG_BANK);
+	if (reg != 0x00)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, REG_VENDOR_ID);
+	if (reg != 0x50)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, REG_CHIP_ID);
+	if (reg != 0xc3)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, REG_VERSION_ID);
+	if (reg < 0 || (reg & 0xf0) != 0x20)
+		return -ENODEV;
+
+	/* Also validate lower bits of voltage and temperature registers */
+	reg = i2c_smbus_read_byte_data(client, REG_TEMP_LSB);
+	if (reg < 0 || (reg & 0x1f))
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, REG_TEMP_PECI_LSB);
+	if (reg < 0 || (reg & 0x3f))
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, REG_VOLTAGE_LOW);
+	if (reg < 0 || (reg & 0x3f))
+		return -ENODEV;
+
+	strlcpy(info->type, "nct7802", I2C_NAME_SIZE);
+	return 0;
+}
+
+static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+	return (reg != REG_BANK && reg <= 0x20) ||
+		(reg >= REG_PWM(0) && reg <= REG_PWM(2));
+}
+
+static const struct regmap_config nct7802_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = nct7802_regmap_is_volatile,
+};
+
+static int nct7802_init_chip(struct nct7802_data *data)
+{
+	int err;
+
+	/* Enable ADC */
+	err = regmap_update_bits(data->regmap, REG_START, 0x01, 0x01);
+	if (err)
+		return err;
+
+	/* Enable local temperature sensor */
+	err = regmap_update_bits(data->regmap, REG_MODE, 0x40, 0x40);
+	if (err)
+		return err;
+
+	/* Enable Vcore and VCC voltage monitoring */
+	return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03);
+}
+
+static int nct7802_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct nct7802_data *data;
+	struct device *hwmon_dev;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	data->regmap = devm_regmap_init_i2c(client, &nct7802_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	mutex_init(&data->access_lock);
+
+	ret = nct7802_init_chip(data);
+	if (ret < 0)
+		return ret;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   nct7802_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const unsigned short nct7802_address_list[] = {
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id nct7802_idtable[] = {
+	{ "nct7802", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nct7802_idtable);
+
+static struct i2c_driver nct7802_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = DRVNAME,
+	},
+	.detect = nct7802_detect,
+	.probe = nct7802_probe,
+	.id_table = nct7802_idtable,
+	.address_list = nct7802_address_list,
+};
+
+module_i2c_driver(nct7802_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT7802Y Hardware Monitoring Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c
new file mode 100644
index 0000000..08ff89d
--- /dev/null
+++ b/drivers/hwmon/nct7904.c
@@ -0,0 +1,595 @@
+/*
+ * nct7904.c - driver for Nuvoton NCT7904D.
+ *
+ * Copyright (c) 2015 Kontron
+ * Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define VENDOR_ID_REG		0x7A	/* Any bank */
+#define NUVOTON_ID		0x50
+#define CHIP_ID_REG		0x7B	/* Any bank */
+#define NCT7904_ID		0xC5
+#define DEVICE_ID_REG		0x7C	/* Any bank */
+
+#define BANK_SEL_REG		0xFF
+#define BANK_0			0x00
+#define BANK_1			0x01
+#define BANK_2			0x02
+#define BANK_3			0x03
+#define BANK_4			0x04
+#define BANK_MAX		0x04
+
+#define FANIN_MAX		12	/* Counted from 1 */
+#define VSEN_MAX		21	/* VSEN1..14, 3VDD, VBAT, V3VSB,
+					   LTD (not a voltage), VSEN17..19 */
+#define FANCTL_MAX		4	/* Counted from 1 */
+#define TCPU_MAX		8	/* Counted from 1 */
+#define TEMP_MAX		4	/* Counted from 1 */
+
+#define VT_ADC_CTRL0_REG	0x20	/* Bank 0 */
+#define VT_ADC_CTRL1_REG	0x21	/* Bank 0 */
+#define VT_ADC_CTRL2_REG	0x22	/* Bank 0 */
+#define FANIN_CTRL0_REG		0x24
+#define FANIN_CTRL1_REG		0x25
+#define DTS_T_CTRL0_REG		0x26
+#define DTS_T_CTRL1_REG		0x27
+#define VT_ADC_MD_REG		0x2E
+
+#define VSEN1_HV_REG		0x40	/* Bank 0; 2 regs (HV/LV) per sensor */
+#define TEMP_CH1_HV_REG		0x42	/* Bank 0; same as VSEN2_HV */
+#define LTD_HV_REG		0x62	/* Bank 0; 2 regs in VSEN range */
+#define FANIN1_HV_REG		0x80	/* Bank 0; 2 regs (HV/LV) per sensor */
+#define T_CPU1_HV_REG		0xA0	/* Bank 0; 2 regs (HV/LV) per sensor */
+
+#define PRTS_REG		0x03	/* Bank 2 */
+#define FANCTL1_FMR_REG		0x00	/* Bank 3; 1 reg per channel */
+#define FANCTL1_OUT_REG		0x10	/* Bank 3; 1 reg per channel */
+
+static const unsigned short normal_i2c[] = {
+	0x2d, 0x2e, I2C_CLIENT_END
+};
+
+struct nct7904_data {
+	struct i2c_client *client;
+	struct mutex bank_lock;
+	int bank_sel;
+	u32 fanin_mask;
+	u32 vsen_mask;
+	u32 tcpu_mask;
+	u8 fan_mode[FANCTL_MAX];
+};
+
+/* Access functions */
+static int nct7904_bank_lock(struct nct7904_data *data, unsigned bank)
+{
+	int ret;
+
+	mutex_lock(&data->bank_lock);
+	if (data->bank_sel == bank)
+		return 0;
+	ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank);
+	if (ret == 0)
+		data->bank_sel = bank;
+	else
+		data->bank_sel = -1;
+	return ret;
+}
+
+static inline void nct7904_bank_release(struct nct7904_data *data)
+{
+	mutex_unlock(&data->bank_lock);
+}
+
+/* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */
+static int nct7904_read_reg(struct nct7904_data *data,
+			    unsigned bank, unsigned reg)
+{
+	struct i2c_client *client = data->client;
+	int ret;
+
+	ret = nct7904_bank_lock(data, bank);
+	if (ret == 0)
+		ret = i2c_smbus_read_byte_data(client, reg);
+
+	nct7904_bank_release(data);
+	return ret;
+}
+
+/*
+ * Read 2-byte register. Returns register in big-endian format or
+ * -ERRNO on error.
+ */
+static int nct7904_read_reg16(struct nct7904_data *data,
+			      unsigned bank, unsigned reg)
+{
+	struct i2c_client *client = data->client;
+	int ret, hi;
+
+	ret = nct7904_bank_lock(data, bank);
+	if (ret == 0) {
+		ret = i2c_smbus_read_byte_data(client, reg);
+		if (ret >= 0) {
+			hi = ret;
+			ret = i2c_smbus_read_byte_data(client, reg + 1);
+			if (ret >= 0)
+				ret |= hi << 8;
+		}
+	}
+
+	nct7904_bank_release(data);
+	return ret;
+}
+
+/* Write 1-byte register. Returns 0 or -ERRNO on error. */
+static int nct7904_write_reg(struct nct7904_data *data,
+			     unsigned bank, unsigned reg, u8 val)
+{
+	struct i2c_client *client = data->client;
+	int ret;
+
+	ret = nct7904_bank_lock(data, bank);
+	if (ret == 0)
+		ret = i2c_smbus_write_byte_data(client, reg, val);
+
+	nct7904_bank_release(data);
+	return ret;
+}
+
+/* FANIN ATTR */
+static ssize_t show_fan(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int ret;
+	unsigned cnt, rpm;
+
+	ret = nct7904_read_reg16(data, BANK_0, FANIN1_HV_REG + index * 2);
+	if (ret < 0)
+		return ret;
+	cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
+	if (cnt == 0x1fff)
+		rpm = 0;
+	else
+		rpm = 1350000 / cnt;
+	return sprintf(buf, "%u\n", rpm);
+}
+
+static umode_t nct7904_fanin_is_visible(struct kobject *kobj,
+					struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7904_data *data = dev_get_drvdata(dev);
+
+	if (data->fanin_mask & (1 << n))
+		return a->mode;
+	return 0;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, show_fan, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, show_fan, NULL, 9);
+static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, show_fan, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, show_fan, NULL, 11);
+
+static struct attribute *nct7904_fanin_attrs[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan5_input.dev_attr.attr,
+	&sensor_dev_attr_fan6_input.dev_attr.attr,
+	&sensor_dev_attr_fan7_input.dev_attr.attr,
+	&sensor_dev_attr_fan8_input.dev_attr.attr,
+	&sensor_dev_attr_fan9_input.dev_attr.attr,
+	&sensor_dev_attr_fan10_input.dev_attr.attr,
+	&sensor_dev_attr_fan11_input.dev_attr.attr,
+	&sensor_dev_attr_fan12_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group nct7904_fanin_group = {
+	.attrs = nct7904_fanin_attrs,
+	.is_visible = nct7904_fanin_is_visible,
+};
+
+/* VSEN ATTR */
+static ssize_t show_voltage(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int ret;
+	int volt;
+
+	ret = nct7904_read_reg16(data, BANK_0, VSEN1_HV_REG + index * 2);
+	if (ret < 0)
+		return ret;
+	volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
+	if (index < 14)
+		volt *= 2; /* 0.002V scale */
+	else
+		volt *= 6; /* 0.006V scale */
+
+	return sprintf(buf, "%d\n", volt);
+}
+
+static ssize_t show_ltemp(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int ret;
+	int temp;
+
+	ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG);
+	if (ret < 0)
+		return ret;
+	temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
+	temp = sign_extend32(temp, 10) * 125;
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static umode_t nct7904_vsen_is_visible(struct kobject *kobj,
+				       struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7904_data *data = dev_get_drvdata(dev);
+
+	if (data->vsen_mask & (1 << n))
+		return a->mode;
+	return 0;
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_voltage, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_voltage, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_voltage, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_voltage, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_voltage, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_voltage, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_voltage, NULL, 13);
+/*
+ * Next 3 voltage sensors have specific names in the Nuvoton doc
+ * (3VDD, VBAT, 3VSB) but we use vacant numbers for them.
+ */
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_voltage, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_voltage, NULL, 15);
+static SENSOR_DEVICE_ATTR(in20_input, S_IRUGO, show_voltage, NULL, 16);
+/* This is not a voltage, but a local temperature sensor. */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_ltemp, NULL, 0);
+static SENSOR_DEVICE_ATTR(in17_input, S_IRUGO, show_voltage, NULL, 18);
+static SENSOR_DEVICE_ATTR(in18_input, S_IRUGO, show_voltage, NULL, 19);
+static SENSOR_DEVICE_ATTR(in19_input, S_IRUGO, show_voltage, NULL, 20);
+
+static struct attribute *nct7904_vsen_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+	&sensor_dev_attr_in14_input.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	&sensor_dev_attr_in16_input.dev_attr.attr,
+	&sensor_dev_attr_in20_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_in17_input.dev_attr.attr,
+	&sensor_dev_attr_in18_input.dev_attr.attr,
+	&sensor_dev_attr_in19_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group nct7904_vsen_group = {
+	.attrs = nct7904_vsen_attrs,
+	.is_visible = nct7904_vsen_is_visible,
+};
+
+/* CPU_TEMP ATTR */
+static ssize_t show_tcpu(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int ret;
+	int temp;
+
+	ret = nct7904_read_reg16(data, BANK_0, T_CPU1_HV_REG + index * 2);
+	if (ret < 0)
+		return ret;
+
+	temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
+	temp = sign_extend32(temp, 10) * 125;
+	return sprintf(buf, "%d\n", temp);
+}
+
+static umode_t nct7904_tcpu_is_visible(struct kobject *kobj,
+				       struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct7904_data *data = dev_get_drvdata(dev);
+
+	if (data->tcpu_mask & (1 << n))
+		return a->mode;
+	return 0;
+}
+
+/* "temp1_input" reserved for local temp */
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_tcpu, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_tcpu, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_tcpu, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_tcpu, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_tcpu, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_tcpu, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_tcpu, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_tcpu, NULL, 7);
+
+static struct attribute *nct7904_tcpu_attrs[] = {
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp9_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group nct7904_tcpu_group = {
+	.attrs = nct7904_tcpu_attrs,
+	.is_visible = nct7904_tcpu_is_visible,
+};
+
+/* PWM ATTR */
+static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val > 255)
+		return -EINVAL;
+
+	ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + index, val);
+
+	return ret ? ret : count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int val;
+
+	val = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + index);
+	if (val < 0)
+		return val;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_enable(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val < 1 || val > 2 || (val == 2 && !data->fan_mode[index]))
+		return -EINVAL;
+
+	ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index,
+				val == 2 ? data->fan_mode[index] : 0);
+
+	return ret ? ret : count;
+}
+
+/* Return 1 for manual mode or 2 for SmartFan mode */
+static ssize_t show_enable(struct device *dev,
+			   struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct nct7904_data *data = dev_get_drvdata(dev);
+	int val;
+
+	val = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + index);
+	if (val < 0)
+		return val;
+
+	return sprintf(buf, "%d\n", val ? 2 : 1);
+}
+
+/* 2 attributes per channel: pwm and mode */
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
+			show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+			show_enable, store_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
+			show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+			show_enable, store_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR,
+			show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+			show_enable, store_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR,
+			show_pwm, store_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
+			show_enable, store_enable, 3);
+
+static struct attribute *nct7904_fanctl_attrs[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.attr,
+	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group nct7904_fanctl_group = {
+	.attrs = nct7904_fanctl_attrs,
+};
+
+static const struct attribute_group *nct7904_groups[] = {
+	&nct7904_fanin_group,
+	&nct7904_vsen_group,
+	&nct7904_tcpu_group,
+	&nct7904_fanctl_group,
+	NULL
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int nct7904_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+
+	if (!i2c_check_functionality(adapter,
+				     I2C_FUNC_SMBUS_READ_BYTE |
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -ENODEV;
+
+	/* Determine the chip type. */
+	if (i2c_smbus_read_byte_data(client, VENDOR_ID_REG) != NUVOTON_ID ||
+	    i2c_smbus_read_byte_data(client, CHIP_ID_REG) != NCT7904_ID ||
+	    (i2c_smbus_read_byte_data(client, DEVICE_ID_REG) & 0xf0) != 0x50 ||
+	    (i2c_smbus_read_byte_data(client, BANK_SEL_REG) & 0xf8) != 0x00)
+		return -ENODEV;
+
+	strlcpy(info->type, "nct7904", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int nct7904_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct nct7904_data *data;
+	struct device *hwmon_dev;
+	struct device *dev = &client->dev;
+	int ret, i;
+	u32 mask;
+
+	data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->bank_lock);
+	data->bank_sel = -1;
+
+	/* Setup sensor groups. */
+	/* FANIN attributes */
+	ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG);
+	if (ret < 0)
+		return ret;
+	data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8);
+
+	/*
+	 * VSEN attributes
+	 *
+	 * Note: voltage sensors overlap with external temperature
+	 * sensors. So, if we ever decide to support the latter
+	 * we will have to adjust 'vsen_mask' accordingly.
+	 */
+	mask = 0;
+	ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG);
+	if (ret >= 0)
+		mask = (ret >> 8) | ((ret & 0xff) << 8);
+	ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
+	if (ret >= 0)
+		mask |= (ret << 16);
+	data->vsen_mask = mask;
+
+	/* CPU_TEMP attributes */
+	ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG);
+	if (ret < 0)
+		return ret;
+	data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4);
+
+	for (i = 0; i < FANCTL_MAX; i++) {
+		ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);
+		if (ret < 0)
+			return ret;
+		data->fan_mode[i] = ret;
+	}
+
+	hwmon_dev =
+		devm_hwmon_device_register_with_groups(dev, client->name, data,
+						       nct7904_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id nct7904_id[] = {
+	{"nct7904", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, nct7904_id);
+
+static struct i2c_driver nct7904_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "nct7904",
+	},
+	.probe = nct7904_probe,
+	.id_table = nct7904_id,
+	.detect = nct7904_detect,
+	.address_list = normal_i2c,
+};
+
+module_i2c_driver(nct7904_driver);
+
+MODULE_AUTHOR("Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>");
+MODULE_DESCRIPTION("Hwmon driver for NUVOTON NCT7904");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
new file mode 100644
index 0000000..feed306
--- /dev/null
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -0,0 +1,679 @@
+/*
+ * ntc_thermistor.c - NTC Thermistors
+ *
+ *  Copyright (C) 2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/math64.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/platform_data/ntc_thermistor.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
+
+struct ntc_compensation {
+	int		temp_c;
+	unsigned int	ohm;
+};
+
+/* Order matters, ntc_match references the entries by index */
+static const struct platform_device_id ntc_thermistor_id[] = {
+	{ "ncp15wb473", TYPE_NCPXXWB473 },
+	{ "ncp18wb473", TYPE_NCPXXWB473 },
+	{ "ncp21wb473", TYPE_NCPXXWB473 },
+	{ "ncp03wb473", TYPE_NCPXXWB473 },
+	{ "ncp15wl333", TYPE_NCPXXWL333 },
+	{ "b57330v2103", TYPE_B57330V2103},
+	{ "ncp03wf104", TYPE_NCPXXWF104 },
+	{ },
+};
+
+/*
+ * A compensation table should be sorted by the values of .ohm
+ * in descending order.
+ * The following compensation tables are from the specification of Murata NTC
+ * Thermistors Datasheet
+ */
+static const struct ntc_compensation ncpXXwb473[] = {
+	{ .temp_c	= -40, .ohm	= 1747920 },
+	{ .temp_c	= -35, .ohm	= 1245428 },
+	{ .temp_c	= -30, .ohm	= 898485 },
+	{ .temp_c	= -25, .ohm	= 655802 },
+	{ .temp_c	= -20, .ohm	= 483954 },
+	{ .temp_c	= -15, .ohm	= 360850 },
+	{ .temp_c	= -10, .ohm	= 271697 },
+	{ .temp_c	= -5, .ohm	= 206463 },
+	{ .temp_c	= 0, .ohm	= 158214 },
+	{ .temp_c	= 5, .ohm	= 122259 },
+	{ .temp_c	= 10, .ohm	= 95227 },
+	{ .temp_c	= 15, .ohm	= 74730 },
+	{ .temp_c	= 20, .ohm	= 59065 },
+	{ .temp_c	= 25, .ohm	= 47000 },
+	{ .temp_c	= 30, .ohm	= 37643 },
+	{ .temp_c	= 35, .ohm	= 30334 },
+	{ .temp_c	= 40, .ohm	= 24591 },
+	{ .temp_c	= 45, .ohm	= 20048 },
+	{ .temp_c	= 50, .ohm	= 16433 },
+	{ .temp_c	= 55, .ohm	= 13539 },
+	{ .temp_c	= 60, .ohm	= 11209 },
+	{ .temp_c	= 65, .ohm	= 9328 },
+	{ .temp_c	= 70, .ohm	= 7798 },
+	{ .temp_c	= 75, .ohm	= 6544 },
+	{ .temp_c	= 80, .ohm	= 5518 },
+	{ .temp_c	= 85, .ohm	= 4674 },
+	{ .temp_c	= 90, .ohm	= 3972 },
+	{ .temp_c	= 95, .ohm	= 3388 },
+	{ .temp_c	= 100, .ohm	= 2902 },
+	{ .temp_c	= 105, .ohm	= 2494 },
+	{ .temp_c	= 110, .ohm	= 2150 },
+	{ .temp_c	= 115, .ohm	= 1860 },
+	{ .temp_c	= 120, .ohm	= 1615 },
+	{ .temp_c	= 125, .ohm	= 1406 },
+};
+static const struct ntc_compensation ncpXXwl333[] = {
+	{ .temp_c	= -40, .ohm	= 1610154 },
+	{ .temp_c	= -35, .ohm	= 1130850 },
+	{ .temp_c	= -30, .ohm	= 802609 },
+	{ .temp_c	= -25, .ohm	= 575385 },
+	{ .temp_c	= -20, .ohm	= 416464 },
+	{ .temp_c	= -15, .ohm	= 304219 },
+	{ .temp_c	= -10, .ohm	= 224193 },
+	{ .temp_c	= -5, .ohm	= 166623 },
+	{ .temp_c	= 0, .ohm	= 124850 },
+	{ .temp_c	= 5, .ohm	= 94287 },
+	{ .temp_c	= 10, .ohm	= 71747 },
+	{ .temp_c	= 15, .ohm	= 54996 },
+	{ .temp_c	= 20, .ohm	= 42455 },
+	{ .temp_c	= 25, .ohm	= 33000 },
+	{ .temp_c	= 30, .ohm	= 25822 },
+	{ .temp_c	= 35, .ohm	= 20335 },
+	{ .temp_c	= 40, .ohm	= 16115 },
+	{ .temp_c	= 45, .ohm	= 12849 },
+	{ .temp_c	= 50, .ohm	= 10306 },
+	{ .temp_c	= 55, .ohm	= 8314 },
+	{ .temp_c	= 60, .ohm	= 6746 },
+	{ .temp_c	= 65, .ohm	= 5503 },
+	{ .temp_c	= 70, .ohm	= 4513 },
+	{ .temp_c	= 75, .ohm	= 3721 },
+	{ .temp_c	= 80, .ohm	= 3084 },
+	{ .temp_c	= 85, .ohm	= 2569 },
+	{ .temp_c	= 90, .ohm	= 2151 },
+	{ .temp_c	= 95, .ohm	= 1809 },
+	{ .temp_c	= 100, .ohm	= 1529 },
+	{ .temp_c	= 105, .ohm	= 1299 },
+	{ .temp_c	= 110, .ohm	= 1108 },
+	{ .temp_c	= 115, .ohm	= 949 },
+	{ .temp_c	= 120, .ohm	= 817 },
+	{ .temp_c	= 125, .ohm	= 707 },
+};
+
+static const struct ntc_compensation ncpXXwf104[] = {
+	{ .temp_c	= -40, .ohm	= 4397119 },
+	{ .temp_c	= -35, .ohm	= 3088599 },
+	{ .temp_c	= -30, .ohm	= 2197225 },
+	{ .temp_c	= -25, .ohm	= 1581881 },
+	{ .temp_c	= -20, .ohm	= 1151037 },
+	{ .temp_c	= -15, .ohm	= 846579 },
+	{ .temp_c	= -10, .ohm	= 628988 },
+	{ .temp_c	= -5, .ohm	= 471632 },
+	{ .temp_c	= 0, .ohm	= 357012 },
+	{ .temp_c	= 5, .ohm	= 272500 },
+	{ .temp_c	= 10, .ohm	= 209710 },
+	{ .temp_c	= 15, .ohm	= 162651 },
+	{ .temp_c	= 20, .ohm	= 127080 },
+	{ .temp_c	= 25, .ohm	= 100000 },
+	{ .temp_c	= 30, .ohm	= 79222 },
+	{ .temp_c	= 35, .ohm	= 63167 },
+	{ .temp_c	= 40, .ohm	= 50677 },
+	{ .temp_c	= 45, .ohm	= 40904 },
+	{ .temp_c	= 50, .ohm	= 33195 },
+	{ .temp_c	= 55, .ohm	= 27091 },
+	{ .temp_c	= 60, .ohm	= 22224 },
+	{ .temp_c	= 65, .ohm	= 18323 },
+	{ .temp_c	= 70, .ohm	= 15184 },
+	{ .temp_c	= 75, .ohm	= 12635 },
+	{ .temp_c	= 80, .ohm	= 10566 },
+	{ .temp_c	= 85, .ohm	= 8873 },
+	{ .temp_c	= 90, .ohm	= 7481 },
+	{ .temp_c	= 95, .ohm	= 6337 },
+	{ .temp_c	= 100, .ohm	= 5384 },
+	{ .temp_c	= 105, .ohm	= 4594 },
+	{ .temp_c	= 110, .ohm	= 3934 },
+	{ .temp_c	= 115, .ohm	= 3380 },
+	{ .temp_c	= 120, .ohm	= 2916 },
+	{ .temp_c	= 125, .ohm	= 2522 },
+};
+
+/*
+ * The following compensation table is from the specification of EPCOS NTC
+ * Thermistors Datasheet
+ */
+static const struct ntc_compensation b57330v2103[] = {
+	{ .temp_c	= -40, .ohm	= 190030 },
+	{ .temp_c	= -35, .ohm	= 145360 },
+	{ .temp_c	= -30, .ohm	= 112060 },
+	{ .temp_c	= -25, .ohm	= 87041 },
+	{ .temp_c	= -20, .ohm	= 68104 },
+	{ .temp_c	= -15, .ohm	= 53665 },
+	{ .temp_c	= -10, .ohm	= 42576 },
+	{ .temp_c	= -5, .ohm	= 34001 },
+	{ .temp_c	= 0, .ohm	= 27326 },
+	{ .temp_c	= 5, .ohm	= 22096 },
+	{ .temp_c	= 10, .ohm	= 17973 },
+	{ .temp_c	= 15, .ohm	= 14703 },
+	{ .temp_c	= 20, .ohm	= 12090 },
+	{ .temp_c	= 25, .ohm	= 10000 },
+	{ .temp_c	= 30, .ohm	= 8311 },
+	{ .temp_c	= 35, .ohm	= 6941 },
+	{ .temp_c	= 40, .ohm	= 5825 },
+	{ .temp_c	= 45, .ohm	= 4911 },
+	{ .temp_c	= 50, .ohm	= 4158 },
+	{ .temp_c	= 55, .ohm	= 3536 },
+	{ .temp_c	= 60, .ohm	= 3019 },
+	{ .temp_c	= 65, .ohm	= 2588 },
+	{ .temp_c	= 70, .ohm	= 2227 },
+	{ .temp_c	= 75, .ohm	= 1924 },
+	{ .temp_c	= 80, .ohm	= 1668 },
+	{ .temp_c	= 85, .ohm	= 1451 },
+	{ .temp_c	= 90, .ohm	= 1266 },
+	{ .temp_c	= 95, .ohm	= 1108 },
+	{ .temp_c	= 100, .ohm	= 973 },
+	{ .temp_c	= 105, .ohm	= 857 },
+	{ .temp_c	= 110, .ohm	= 757 },
+	{ .temp_c	= 115, .ohm	= 671 },
+	{ .temp_c	= 120, .ohm	= 596 },
+	{ .temp_c	= 125, .ohm	= 531 },
+};
+
+struct ntc_data {
+	struct device *hwmon_dev;
+	struct ntc_thermistor_platform_data *pdata;
+	const struct ntc_compensation *comp;
+	struct device *dev;
+	int n_comp;
+	char name[PLATFORM_NAME_SIZE];
+	struct thermal_zone_device *tz;
+};
+
+#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO)
+static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
+{
+	struct iio_channel *channel = pdata->chan;
+	int raw, uv, ret;
+
+	ret = iio_read_channel_raw(channel, &raw);
+	if (ret < 0) {
+		pr_err("read channel() error: %d\n", ret);
+		return ret;
+	}
+
+	ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
+	if (ret < 0) {
+		/* Assume 12 bit ADC with vref at pullup_uv */
+		uv = (pdata->pullup_uv * (s64)raw) >> 12;
+	}
+
+	return uv;
+}
+
+static const struct of_device_id ntc_match[] = {
+	{ .compatible = "murata,ncp15wb473",
+		.data = &ntc_thermistor_id[0] },
+	{ .compatible = "murata,ncp18wb473",
+		.data = &ntc_thermistor_id[1] },
+	{ .compatible = "murata,ncp21wb473",
+		.data = &ntc_thermistor_id[2] },
+	{ .compatible = "murata,ncp03wb473",
+		.data = &ntc_thermistor_id[3] },
+	{ .compatible = "murata,ncp15wl333",
+		.data = &ntc_thermistor_id[4] },
+	{ .compatible = "epcos,b57330v2103",
+		.data = &ntc_thermistor_id[5]},
+	{ .compatible = "murata,ncp03wf104",
+		.data = &ntc_thermistor_id[6] },
+
+	/* Usage of vendor name "ntc" is deprecated */
+	{ .compatible = "ntc,ncp15wb473",
+		.data = &ntc_thermistor_id[0] },
+	{ .compatible = "ntc,ncp18wb473",
+		.data = &ntc_thermistor_id[1] },
+	{ .compatible = "ntc,ncp21wb473",
+		.data = &ntc_thermistor_id[2] },
+	{ .compatible = "ntc,ncp03wb473",
+		.data = &ntc_thermistor_id[3] },
+	{ .compatible = "ntc,ncp15wl333",
+		.data = &ntc_thermistor_id[4] },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ntc_match);
+
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+	struct iio_channel *chan;
+	enum iio_chan_type type;
+	struct device_node *np = pdev->dev.of_node;
+	struct ntc_thermistor_platform_data *pdata;
+	int ret;
+
+	if (!np)
+		return NULL;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	chan = iio_channel_get(&pdev->dev, NULL);
+	if (IS_ERR(chan))
+		return ERR_CAST(chan);
+
+	ret = iio_get_channel_type(chan, &type);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	if (type != IIO_VOLTAGE)
+		return ERR_PTR(-EINVAL);
+
+	if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
+		return ERR_PTR(-ENODEV);
+	if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
+		return ERR_PTR(-ENODEV);
+	if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
+		return ERR_PTR(-ENODEV);
+
+	if (of_find_property(np, "connected-positive", NULL))
+		pdata->connect = NTC_CONNECTED_POSITIVE;
+	else /* status change should be possible if not always on. */
+		pdata->connect = NTC_CONNECTED_GROUND;
+
+	pdata->chan = chan;
+	pdata->read_uv = ntc_adc_iio_read;
+
+	return pdata;
+}
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{
+	if (pdata->chan)
+		iio_channel_release(pdata->chan);
+}
+#else
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+	return NULL;
+}
+
+#define ntc_match	NULL
+
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{ }
+#endif
+
+static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
+{
+	if (divisor == 0 && dividend == 0)
+		return 0;
+	if (divisor == 0)
+		return UINT_MAX;
+	return div64_u64(dividend, divisor);
+}
+
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
+{
+	struct ntc_thermistor_platform_data *pdata = data->pdata;
+	u32 puv = pdata->pullup_uv;
+	u64 n, puo, pdo;
+	puo = pdata->pullup_ohm;
+	pdo = pdata->pulldown_ohm;
+
+	if (uv == 0)
+		return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
+			INT_MAX : 0;
+	if (uv >= puv)
+		return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
+			0 : INT_MAX;
+
+	if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
+		n = div_u64(pdo * (puv - uv), uv);
+	else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
+		n = div_u64(puo * uv, puv - uv);
+	else if (pdata->connect == NTC_CONNECTED_POSITIVE)
+		n = div64_u64_safe(pdo * puo * (puv - uv),
+				puo * uv - pdo * (puv - uv));
+	else
+		n = div64_u64_safe(pdo * puo * uv, pdo * (puv - uv) - puo * uv);
+
+	if (n > INT_MAX)
+		n = INT_MAX;
+	return n;
+}
+
+static void lookup_comp(struct ntc_data *data, unsigned int ohm,
+			int *i_low, int *i_high)
+{
+	int start, end, mid;
+
+	/*
+	 * Handle special cases: Resistance is higher than or equal to
+	 * resistance in first table entry, or resistance is lower or equal
+	 * to resistance in last table entry.
+	 * In these cases, return i_low == i_high, either pointing to the
+	 * beginning or to the end of the table depending on the condition.
+	 */
+	if (ohm >= data->comp[0].ohm) {
+		*i_low = 0;
+		*i_high = 0;
+		return;
+	}
+	if (ohm <= data->comp[data->n_comp - 1].ohm) {
+		*i_low = data->n_comp - 1;
+		*i_high = data->n_comp - 1;
+		return;
+	}
+
+	/* Do a binary search on compensation table */
+	start = 0;
+	end = data->n_comp;
+	while (start < end) {
+		mid = start + (end - start) / 2;
+		/*
+		 * start <= mid < end
+		 * data->comp[start].ohm > ohm >= data->comp[end].ohm
+		 *
+		 * We could check for "ohm == data->comp[mid].ohm" here, but
+		 * that is a quite unlikely condition, and we would have to
+		 * check again after updating start. Check it at the end instead
+		 * for simplicity.
+		 */
+		if (ohm >= data->comp[mid].ohm) {
+			end = mid;
+		} else {
+			start = mid + 1;
+			/*
+			 * ohm >= data->comp[start].ohm might be true here,
+			 * since we set start to mid + 1. In that case, we are
+			 * done. We could keep going, but the condition is quite
+			 * likely to occur, so it is worth checking for it.
+			 */
+			if (ohm >= data->comp[start].ohm)
+				end = start;
+		}
+		/*
+		 * start <= end
+		 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
+		 */
+	}
+	/*
+	 * start == end
+	 * ohm >= data->comp[end].ohm
+	 */
+	*i_low = end;
+	if (ohm == data->comp[end].ohm)
+		*i_high = end;
+	else
+		*i_high = end - 1;
+}
+
+static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
+{
+	int low, high;
+	int temp;
+
+	lookup_comp(data, ohm, &low, &high);
+	if (low == high) {
+		/* Unable to use linear approximation */
+		temp = data->comp[low].temp_c * 1000;
+	} else {
+		temp = data->comp[low].temp_c * 1000 +
+			((data->comp[high].temp_c - data->comp[low].temp_c) *
+			 1000 * ((int)ohm - (int)data->comp[low].ohm)) /
+			((int)data->comp[high].ohm - (int)data->comp[low].ohm);
+	}
+	return temp;
+}
+
+static int ntc_thermistor_get_ohm(struct ntc_data *data)
+{
+	int read_uv;
+
+	if (data->pdata->read_ohm)
+		return data->pdata->read_ohm();
+
+	if (data->pdata->read_uv) {
+		read_uv = data->pdata->read_uv(data->pdata);
+		if (read_uv < 0)
+			return read_uv;
+		return get_ohm_of_thermistor(data, read_uv);
+	}
+	return -EINVAL;
+}
+
+static int ntc_read_temp(void *dev, int *temp)
+{
+	struct ntc_data *data = dev_get_drvdata(dev);
+	int ohm;
+
+	ohm = ntc_thermistor_get_ohm(data);
+	if (ohm < 0)
+		return ohm;
+
+	*temp = get_temp_mc(data, ohm);
+
+	return 0;
+}
+
+static ssize_t ntc_show_name(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ntc_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t ntc_show_type(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "4\n");
+}
+
+static ssize_t ntc_show_temp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ntc_data *data = dev_get_drvdata(dev);
+	int ohm;
+
+	ohm = ntc_thermistor_get_ohm(data);
+	if (ohm < 0)
+		return ohm;
+
+	return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
+static DEVICE_ATTR(name, S_IRUGO, ntc_show_name, NULL);
+
+static struct attribute *ntc_attributes[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ntc_attr_group = {
+	.attrs = ntc_attributes,
+};
+
+static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = {
+	.get_temp = ntc_read_temp,
+};
+
+static int ntc_thermistor_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(of_match_ptr(ntc_match), &pdev->dev);
+	const struct platform_device_id *pdev_id;
+	struct ntc_thermistor_platform_data *pdata;
+	struct ntc_data *data;
+	int ret;
+
+	pdata = ntc_thermistor_parse_dt(pdev);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+	else if (pdata == NULL)
+		pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform init data supplied.\n");
+		return -ENODEV;
+	}
+
+	/* Either one of the two is required. */
+	if (!pdata->read_uv && !pdata->read_ohm) {
+		dev_err(&pdev->dev,
+			"Both read_uv and read_ohm missing. Need either one of the two.\n");
+		return -EINVAL;
+	}
+
+	if (pdata->read_uv && pdata->read_ohm) {
+		dev_warn(&pdev->dev,
+			 "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
+		pdata->read_uv = NULL;
+	}
+
+	if (pdata->read_uv && (pdata->pullup_uv == 0 ||
+				(pdata->pullup_ohm == 0 && pdata->connect ==
+				 NTC_CONNECTED_GROUND) ||
+				(pdata->pulldown_ohm == 0 && pdata->connect ==
+				 NTC_CONNECTED_POSITIVE) ||
+				(pdata->connect != NTC_CONNECTED_POSITIVE &&
+				 pdata->connect != NTC_CONNECTED_GROUND))) {
+		dev_err(&pdev->dev,
+			"Required data to use read_uv not supplied.\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+	data->dev = &pdev->dev;
+	data->pdata = pdata;
+	strlcpy(data->name, pdev_id->name, sizeof(data->name));
+
+	switch (pdev_id->driver_data) {
+	case TYPE_NCPXXWB473:
+		data->comp = ncpXXwb473;
+		data->n_comp = ARRAY_SIZE(ncpXXwb473);
+		break;
+	case TYPE_NCPXXWL333:
+		data->comp = ncpXXwl333;
+		data->n_comp = ARRAY_SIZE(ncpXXwl333);
+		break;
+	case TYPE_B57330V2103:
+		data->comp = b57330v2103;
+		data->n_comp = ARRAY_SIZE(b57330v2103);
+		break;
+	case TYPE_NCPXXWF104:
+		data->comp = ncpXXwf104;
+		data->n_comp = ARRAY_SIZE(ncpXXwf104);
+		break;
+	default:
+		dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
+				pdev_id->driver_data, pdev_id->name);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
+	if (ret) {
+		dev_err(data->dev, "unable to create sysfs files\n");
+		return ret;
+	}
+
+	data->hwmon_dev = hwmon_device_register(data->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(data->dev, "unable to register as hwmon device.\n");
+		ret = PTR_ERR(data->hwmon_dev);
+		goto err_after_sysfs;
+	}
+
+	dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
+								pdev_id->name);
+
+	data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev,
+						   &ntc_of_thermal_ops);
+	if (IS_ERR(data->tz)) {
+		dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n");
+		data->tz = NULL;
+	}
+
+	return 0;
+err_after_sysfs:
+	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+	ntc_iio_channel_release(pdata);
+	return ret;
+}
+
+static int ntc_thermistor_remove(struct platform_device *pdev)
+{
+	struct ntc_data *data = platform_get_drvdata(pdev);
+	struct ntc_thermistor_platform_data *pdata = data->pdata;
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+	ntc_iio_channel_release(pdata);
+
+	thermal_zone_of_sensor_unregister(data->dev, data->tz);
+
+	return 0;
+}
+
+static struct platform_driver ntc_thermistor_driver = {
+	.driver = {
+		.name = "ntc-thermistor",
+		.of_match_table = of_match_ptr(ntc_match),
+	},
+	.probe = ntc_thermistor_probe,
+	.remove = ntc_thermistor_remove,
+	.id_table = ntc_thermistor_id,
+};
+
+module_platform_driver(ntc_thermistor_driver);
+
+MODULE_DESCRIPTION("NTC Thermistor Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ntc-thermistor");
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
new file mode 100644
index 0000000..d50fbf9
--- /dev/null
+++ b/drivers/hwmon/pc87360.c
@@ -0,0 +1,1818 @@
+/*
+ *  pc87360.c - Part of lm_sensors, Linux kernel modules
+ *              for hardware monitoring
+ *  Copyright (C) 2004, 2007 Jean Delvare <jdelvare@suse.de>
+ *
+ *  Copied from smsc47m1.c:
+ *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ *
+ *  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.
+ *
+ *  Supports the following chips:
+ *
+ *  Chip        #vin    #fan    #pwm    #temp   devid
+ *  PC87360     -       2       2       -       0xE1
+ *  PC87363     -       2       2       -       0xE8
+ *  PC87364     -       3       3       -       0xE4
+ *  PC87365     11      3       3       2       0xE5
+ *  PC87366     11      3       3       3-4     0xE9
+ *
+ *  This driver assumes that no more than one chip is present, and one of
+ *  the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static u8 devid;
+static struct platform_device *pdev;
+static unsigned short extra_isa[3];
+static u8 confreg[4];
+
+static int init = 1;
+module_param(init, int, 0);
+MODULE_PARM_DESC(init,
+"Chip initialization level:\n"
+" 0: None\n"
+"*1: Forcibly enable internal voltage and temperature channels, except in9\n"
+" 2: Forcibly enable all voltage and temperature channels, except in9\n"
+" 3: Forcibly enable all voltage and temperature channels, including in9");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Super-I/O registers and operations
+ */
+
+#define DEV	0x07	/* Register: Logical device select */
+#define DEVID	0x20	/* Register: Device ID */
+#define ACT	0x30	/* Register: Device activation */
+#define BASE	0x60	/* Register: Base address */
+
+#define FSCM	0x09	/* Logical device: fans */
+#define VLM	0x0d	/* Logical device: voltages */
+#define TMS	0x0e	/* Logical device: temperatures */
+#define LDNI_MAX 3
+static const u8 logdev[LDNI_MAX] = { FSCM, VLM, TMS };
+
+#define LD_FAN		0
+#define LD_IN		1
+#define LD_TEMP		2
+
+static inline void superio_outb(int sioaddr, int reg, int val)
+{
+	outb(reg, sioaddr);
+	outb(val, sioaddr + 1);
+}
+
+static inline int superio_inb(int sioaddr, int reg)
+{
+	outb(reg, sioaddr);
+	return inb(sioaddr + 1);
+}
+
+static inline void superio_exit(int sioaddr)
+{
+	outb(0x02, sioaddr);
+	outb(0x02, sioaddr + 1);
+}
+
+/*
+ * Logical devices
+ */
+
+#define PC87360_EXTENT		0x10
+#define PC87365_REG_BANK	0x09
+#define NO_BANK			0xff
+
+/*
+ * Fan registers and conversions
+ */
+
+/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */
+#define PC87360_REG_PRESCALE(nr)	(0x00 + 2 * (nr))
+#define PC87360_REG_PWM(nr)		(0x01 + 2 * (nr))
+#define PC87360_REG_FAN_MIN(nr)		(0x06 + 3 * (nr))
+#define PC87360_REG_FAN(nr)		(0x07 + 3 * (nr))
+#define PC87360_REG_FAN_STATUS(nr)	(0x08 + 3 * (nr))
+
+#define FAN_FROM_REG(val, div)		((val) == 0 ? 0 : \
+					 480000 / ((val) * (div)))
+#define FAN_TO_REG(val, div)		((val) <= 100 ? 0 : \
+					 480000 / ((val) * (div)))
+#define FAN_DIV_FROM_REG(val)		(1 << (((val) >> 5) & 0x03))
+#define FAN_STATUS_FROM_REG(val)	((val) & 0x07)
+
+#define FAN_CONFIG_MONITOR(val, nr)	(((val) >> (2 + (nr) * 3)) & 1)
+#define FAN_CONFIG_CONTROL(val, nr)	(((val) >> (3 + (nr) * 3)) & 1)
+#define FAN_CONFIG_INVERT(val, nr)	(((val) >> (4 + (nr) * 3)) & 1)
+
+#define PWM_FROM_REG(val, inv)		((inv) ? 255 - (val) : (val))
+static inline u8 PWM_TO_REG(int val, int inv)
+{
+	if (inv)
+		val = 255 - val;
+	if (val < 0)
+		return 0;
+	if (val > 255)
+		return 255;
+	return val;
+}
+
+/*
+ * Voltage registers and conversions
+ */
+
+#define PC87365_REG_IN_CONVRATE		0x07
+#define PC87365_REG_IN_CONFIG		0x08
+#define PC87365_REG_IN			0x0B
+#define PC87365_REG_IN_MIN		0x0D
+#define PC87365_REG_IN_MAX		0x0C
+#define PC87365_REG_IN_STATUS		0x0A
+#define PC87365_REG_IN_ALARMS1		0x00
+#define PC87365_REG_IN_ALARMS2		0x01
+#define PC87365_REG_VID			0x06
+
+#define IN_FROM_REG(val, ref)		(((val) * (ref) + 128) / 256)
+#define IN_TO_REG(val, ref)		((val) < 0 ? 0 : \
+					 (val) * 256 >= (ref) * 255 ? 255 : \
+					 ((val) * 256 + (ref) / 2) / (ref))
+
+/*
+ * Temperature registers and conversions
+ */
+
+#define PC87365_REG_TEMP_CONFIG		0x08
+#define PC87365_REG_TEMP		0x0B
+#define PC87365_REG_TEMP_MIN		0x0D
+#define PC87365_REG_TEMP_MAX		0x0C
+#define PC87365_REG_TEMP_CRIT		0x0E
+#define PC87365_REG_TEMP_STATUS		0x0A
+#define PC87365_REG_TEMP_ALARMS		0x00
+
+#define TEMP_FROM_REG(val)		((val) * 1000)
+#define TEMP_TO_REG(val)		((val) < -55000 ? -55 : \
+					 (val) > 127000 ? 127 : \
+					 (val) < 0 ? ((val) - 500) / 1000 : \
+					 ((val) + 500) / 1000)
+
+/*
+ * Device data
+ */
+
+struct pc87360_data {
+	const char *name;
+	struct device *hwmon_dev;
+	struct mutex lock;
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	int address[3];
+
+	u8 fannr, innr, tempnr;
+
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	u8 fan_status[3];	/* Register value */
+	u8 pwm[3];		/* Register value */
+	u16 fan_conf;		/* Configuration register values, combined */
+
+	u16 in_vref;		/* 1 mV/bit */
+	u8 in[14];		/* Register value */
+	u8 in_min[14];		/* Register value */
+	u8 in_max[14];		/* Register value */
+	u8 in_crit[3];		/* Register value */
+	u8 in_status[14];	/* Register value */
+	u16 in_alarms;		/* Register values, combined, masked */
+	u8 vid_conf;		/* Configuration register value */
+	u8 vrm;
+	u8 vid;			/* Register value */
+
+	s8 temp[3];		/* Register value */
+	s8 temp_min[3];		/* Register value */
+	s8 temp_max[3];		/* Register value */
+	s8 temp_crit[3];	/* Register value */
+	u8 temp_status[3];	/* Register value */
+	u8 temp_alarms;		/* Register value, masked */
+};
+
+/*
+ * Functions declaration
+ */
+
+static int pc87360_probe(struct platform_device *pdev);
+static int pc87360_remove(struct platform_device *pdev);
+
+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
+			      u8 reg);
+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
+				u8 reg, u8 value);
+static void pc87360_init_device(struct platform_device *pdev,
+				int use_thermistors);
+static struct pc87360_data *pc87360_update_device(struct device *dev);
+
+/*
+ * Driver data
+ */
+
+static struct platform_driver pc87360_driver = {
+	.driver = {
+		.name	= "pc87360",
+	},
+	.probe		= pc87360_probe,
+	.remove		= pc87360_remove,
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_fan_input(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
+		       FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_min(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
+		       FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_div(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n",
+		       FAN_DIV_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t show_fan_status(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n",
+		       FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t set_fan_min(struct device *dev,
+			   struct device_attribute *devattr, const char *buf,
+	size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long fan_min;
+	int err;
+
+	err = kstrtol(buf, 10, &fan_min);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	fan_min = FAN_TO_REG(fan_min,
+			     FAN_DIV_FROM_REG(data->fan_status[attr->index]));
+
+	/* If it wouldn't fit, change clock divisor */
+	while (fan_min > 255
+	    && (data->fan_status[attr->index] & 0x60) != 0x60) {
+		fan_min >>= 1;
+		data->fan[attr->index] >>= 1;
+		data->fan_status[attr->index] += 0x20;
+	}
+	data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
+	pc87360_write_value(data, LD_FAN, NO_BANK,
+			    PC87360_REG_FAN_MIN(attr->index),
+			    data->fan_min[attr->index]);
+
+	/* Write new divider, preserve alarm bits */
+	pc87360_write_value(data, LD_FAN, NO_BANK,
+			    PC87360_REG_FAN_STATUS(attr->index),
+			    data->fan_status[attr->index] & 0xF9);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2),
+};
+static struct sensor_device_attribute fan_status[] = {
+	SENSOR_ATTR(fan1_status, S_IRUGO, show_fan_status, NULL, 0),
+	SENSOR_ATTR(fan2_status, S_IRUGO, show_fan_status, NULL, 1),
+	SENSOR_ATTR(fan3_status, S_IRUGO, show_fan_status, NULL, 2),
+};
+static struct sensor_device_attribute fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+};
+static struct sensor_device_attribute fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 1),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
+};
+
+#define FAN_UNIT_ATTRS(X)		\
+{	&fan_input[X].dev_attr.attr,	\
+	&fan_status[X].dev_attr.attr,	\
+	&fan_div[X].dev_attr.attr,	\
+	&fan_min[X].dev_attr.attr,	\
+	NULL				\
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n",
+		       PWM_FROM_REG(data->pwm[attr->index],
+				    FAN_CONFIG_INVERT(data->fan_conf,
+						      attr->index)));
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[attr->index] = PWM_TO_REG(val,
+			      FAN_CONFIG_INVERT(data->fan_conf, attr->index));
+	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
+			    data->pwm[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1),
+	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
+};
+
+static struct attribute *pc8736x_fan_attr[][5] = {
+	FAN_UNIT_ATTRS(0),
+	FAN_UNIT_ATTRS(1),
+	FAN_UNIT_ATTRS(2)
+};
+
+static const struct attribute_group pc8736x_fan_attr_group[] = {
+	{ .attrs = pc8736x_fan_attr[0], },
+	{ .attrs = pc8736x_fan_attr[1], },
+	{ .attrs = pc8736x_fan_attr[2], },
+};
+
+static ssize_t show_in_input(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_in_min(struct device *dev,
+			   struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_in_max(struct device *dev,
+			   struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_in_status(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
+			    data->in_min[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[attr->index] = IN_TO_REG(val,
+			       data->in_vref);
+	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
+			    data->in_max[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in_input, NULL, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in_input, NULL, 8),
+	SENSOR_ATTR(in9_input, S_IRUGO, show_in_input, NULL, 9),
+	SENSOR_ATTR(in10_input, S_IRUGO, show_in_input, NULL, 10),
+};
+static struct sensor_device_attribute in_status[] = {
+	SENSOR_ATTR(in0_status, S_IRUGO, show_in_status, NULL, 0),
+	SENSOR_ATTR(in1_status, S_IRUGO, show_in_status, NULL, 1),
+	SENSOR_ATTR(in2_status, S_IRUGO, show_in_status, NULL, 2),
+	SENSOR_ATTR(in3_status, S_IRUGO, show_in_status, NULL, 3),
+	SENSOR_ATTR(in4_status, S_IRUGO, show_in_status, NULL, 4),
+	SENSOR_ATTR(in5_status, S_IRUGO, show_in_status, NULL, 5),
+	SENSOR_ATTR(in6_status, S_IRUGO, show_in_status, NULL, 6),
+	SENSOR_ATTR(in7_status, S_IRUGO, show_in_status, NULL, 7),
+	SENSOR_ATTR(in8_status, S_IRUGO, show_in_status, NULL, 8),
+	SENSOR_ATTR(in9_status, S_IRUGO, show_in_status, NULL, 9),
+	SENSOR_ATTR(in10_status, S_IRUGO, show_in_status, NULL, 10),
+};
+static struct sensor_device_attribute in_min[] = {
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 9),
+	SENSOR_ATTR(in10_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 10),
+};
+static struct sensor_device_attribute in_max[] = {
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 9),
+	SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
+};
+
+/* (temp & vin) channel status register alarm bits (pdf sec.11.5.12) */
+#define CHAN_ALM_MIN	0x02	/* min limit crossed */
+#define CHAN_ALM_MAX	0x04	/* max limit exceeded */
+#define TEMP_ALM_CRIT	0x08	/* temp crit exceeded (temp only) */
+
+/*
+ * show_in_min/max_alarm() reads data from the per-channel status
+ * register (sec 11.5.12), not the vin event status registers (sec
+ * 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms)
+ */
+
+static ssize_t show_in_min_alarm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
+}
+static ssize_t show_in_max_alarm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
+}
+
+static struct sensor_device_attribute in_min_alarm[] = {
+	SENSOR_ATTR(in0_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 0),
+	SENSOR_ATTR(in1_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 1),
+	SENSOR_ATTR(in2_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 2),
+	SENSOR_ATTR(in3_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 3),
+	SENSOR_ATTR(in4_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 4),
+	SENSOR_ATTR(in5_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 5),
+	SENSOR_ATTR(in6_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 6),
+	SENSOR_ATTR(in7_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 7),
+	SENSOR_ATTR(in8_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 8),
+	SENSOR_ATTR(in9_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 9),
+	SENSOR_ATTR(in10_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 10),
+};
+static struct sensor_device_attribute in_max_alarm[] = {
+	SENSOR_ATTR(in0_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 0),
+	SENSOR_ATTR(in1_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 1),
+	SENSOR_ATTR(in2_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 2),
+	SENSOR_ATTR(in3_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 3),
+	SENSOR_ATTR(in4_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 4),
+	SENSOR_ATTR(in5_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 5),
+	SENSOR_ATTR(in6_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 6),
+	SENSOR_ATTR(in7_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 7),
+	SENSOR_ATTR(in8_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 8),
+	SENSOR_ATTR(in9_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 9),
+	SENSOR_ATTR(in10_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 10),
+};
+
+#define VIN_UNIT_ATTRS(X) \
+	&in_input[X].dev_attr.attr,	\
+	&in_status[X].dev_attr.attr,	\
+	&in_min[X].dev_attr.attr,	\
+	&in_max[X].dev_attr.attr,	\
+	&in_min_alarm[X].dev_attr.attr,	\
+	&in_max_alarm[X].dev_attr.attr
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_in_alarms(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->in_alarms);
+}
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+
+static struct attribute *pc8736x_vin_attr_array[] = {
+	VIN_UNIT_ATTRS(0),
+	VIN_UNIT_ATTRS(1),
+	VIN_UNIT_ATTRS(2),
+	VIN_UNIT_ATTRS(3),
+	VIN_UNIT_ATTRS(4),
+	VIN_UNIT_ATTRS(5),
+	VIN_UNIT_ATTRS(6),
+	VIN_UNIT_ATTRS(7),
+	VIN_UNIT_ATTRS(8),
+	VIN_UNIT_ATTRS(9),
+	VIN_UNIT_ATTRS(10),
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&dev_attr_alarms_in.attr,
+	NULL
+};
+static const struct attribute_group pc8736x_vin_group = {
+	.attrs = pc8736x_vin_attr_array,
+};
+
+static ssize_t show_therm_input(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_therm_min(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_therm_max(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+		       data->in_vref));
+}
+static ssize_t show_therm_crit(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
+		       data->in_vref));
+}
+static ssize_t show_therm_status(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+
+static ssize_t set_therm_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
+			    data->in_min[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_therm_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
+	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
+			    data->in_max[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_therm_crit(struct device *dev,
+			      struct device_attribute *devattr,
+			      const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
+	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
+			    data->in_crit[attr->index-11]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * the +11 term below reflects the fact that VLM units 11,12,13 are
+ * used in the chip to measure voltage across the thermistors
+ */
+static struct sensor_device_attribute therm_input[] = {
+	SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0 + 11),
+	SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1 + 11),
+	SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2 + 11),
+};
+static struct sensor_device_attribute therm_status[] = {
+	SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0 + 11),
+	SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1 + 11),
+	SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2 + 11),
+};
+static struct sensor_device_attribute therm_min[] = {
+	SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 0 + 11),
+	SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 1 + 11),
+	SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 2 + 11),
+};
+static struct sensor_device_attribute therm_max[] = {
+	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 0 + 11),
+	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 1 + 11),
+	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 2 + 11),
+};
+static struct sensor_device_attribute therm_crit[] = {
+	SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 0 + 11),
+	SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 1 + 11),
+	SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 2 + 11),
+};
+
+/*
+ * show_therm_min/max_alarm() reads data from the per-channel voltage
+ * status register (sec 11.5.12)
+ */
+
+static ssize_t show_therm_min_alarm(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
+}
+static ssize_t show_therm_max_alarm(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
+}
+static ssize_t show_therm_crit_alarm(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->in_status[nr] & TEMP_ALM_CRIT));
+}
+
+static struct sensor_device_attribute therm_min_alarm[] = {
+	SENSOR_ATTR(temp4_min_alarm, S_IRUGO,
+		    show_therm_min_alarm, NULL, 0 + 11),
+	SENSOR_ATTR(temp5_min_alarm, S_IRUGO,
+		    show_therm_min_alarm, NULL, 1 + 11),
+	SENSOR_ATTR(temp6_min_alarm, S_IRUGO,
+		    show_therm_min_alarm, NULL, 2 + 11),
+};
+static struct sensor_device_attribute therm_max_alarm[] = {
+	SENSOR_ATTR(temp4_max_alarm, S_IRUGO,
+		    show_therm_max_alarm, NULL, 0 + 11),
+	SENSOR_ATTR(temp5_max_alarm, S_IRUGO,
+		    show_therm_max_alarm, NULL, 1 + 11),
+	SENSOR_ATTR(temp6_max_alarm, S_IRUGO,
+		    show_therm_max_alarm, NULL, 2 + 11),
+};
+static struct sensor_device_attribute therm_crit_alarm[] = {
+	SENSOR_ATTR(temp4_crit_alarm, S_IRUGO,
+		    show_therm_crit_alarm, NULL, 0 + 11),
+	SENSOR_ATTR(temp5_crit_alarm, S_IRUGO,
+		    show_therm_crit_alarm, NULL, 1 + 11),
+	SENSOR_ATTR(temp6_crit_alarm, S_IRUGO,
+		    show_therm_crit_alarm, NULL, 2 + 11),
+};
+
+#define THERM_UNIT_ATTRS(X) \
+	&therm_input[X].dev_attr.attr,	\
+	&therm_status[X].dev_attr.attr,	\
+	&therm_min[X].dev_attr.attr,	\
+	&therm_max[X].dev_attr.attr,	\
+	&therm_crit[X].dev_attr.attr,	\
+	&therm_min_alarm[X].dev_attr.attr, \
+	&therm_max_alarm[X].dev_attr.attr, \
+	&therm_crit_alarm[X].dev_attr.attr
+
+static struct attribute *pc8736x_therm_attr_array[] = {
+	THERM_UNIT_ATTRS(0),
+	THERM_UNIT_ATTRS(1),
+	THERM_UNIT_ATTRS(2),
+	NULL
+};
+static const struct attribute_group pc8736x_therm_group = {
+	.attrs = pc8736x_therm_attr_array,
+};
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t show_temp_min(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+			      struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       TEMP_FROM_REG(data->temp_crit[attr->index]));
+}
+
+static ssize_t show_temp_status(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_status[attr->index]);
+}
+
+static ssize_t set_temp_min(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[attr->index] = TEMP_TO_REG(val);
+	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
+			    data->temp_min[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[attr->index] = TEMP_TO_REG(val);
+	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
+			    data->temp_max[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_crit(struct device *dev,
+			     struct device_attribute *devattr, const char *buf,
+			     size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_crit[attr->index] = TEMP_TO_REG(val);
+	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
+			    data->temp_crit[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute temp_input[] = {
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2),
+};
+static struct sensor_device_attribute temp_status[] = {
+	SENSOR_ATTR(temp1_status, S_IRUGO, show_temp_status, NULL, 0),
+	SENSOR_ATTR(temp2_status, S_IRUGO, show_temp_status, NULL, 1),
+	SENSOR_ATTR(temp3_status, S_IRUGO, show_temp_status, NULL, 2),
+};
+static struct sensor_device_attribute temp_min[] = {
+	SENSOR_ATTR(temp1_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 0),
+	SENSOR_ATTR(temp2_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 1),
+	SENSOR_ATTR(temp3_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 2),
+};
+static struct sensor_device_attribute temp_max[] = {
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 0),
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 1),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 2),
+};
+static struct sensor_device_attribute temp_crit[] = {
+	SENSOR_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 0),
+	SENSOR_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 1),
+	SENSOR_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 2),
+};
+
+static ssize_t show_temp_alarms(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->temp_alarms);
+}
+
+static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+
+/*
+ * show_temp_min/max_alarm() reads data from the per-channel status
+ * register (sec 12.3.7), not the temp event status registers (sec
+ * 12.3.2) that show_temp_alarm() reads (via data->temp_alarms)
+ */
+
+static ssize_t show_temp_min_alarm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN));
+}
+
+static ssize_t show_temp_max_alarm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX));
+}
+
+static ssize_t show_temp_crit_alarm(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_ALM_CRIT));
+}
+
+static struct sensor_device_attribute temp_min_alarm[] = {
+	SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 0),
+	SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1),
+	SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2),
+};
+
+static struct sensor_device_attribute temp_max_alarm[] = {
+	SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0),
+	SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1),
+	SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2),
+};
+
+static struct sensor_device_attribute temp_crit_alarm[] = {
+	SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0),
+	SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1),
+	SENSOR_ATTR(temp3_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 2),
+};
+
+#define TEMP_FAULT	0x40	/* open diode */
+static ssize_t show_temp_fault(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_FAULT));
+}
+static struct sensor_device_attribute temp_fault[] = {
+	SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
+	SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
+	SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2),
+};
+
+#define TEMP_UNIT_ATTRS(X)			\
+{	&temp_input[X].dev_attr.attr,		\
+	&temp_status[X].dev_attr.attr,		\
+	&temp_min[X].dev_attr.attr,		\
+	&temp_max[X].dev_attr.attr,		\
+	&temp_crit[X].dev_attr.attr,		\
+	&temp_min_alarm[X].dev_attr.attr,	\
+	&temp_max_alarm[X].dev_attr.attr,	\
+	&temp_crit_alarm[X].dev_attr.attr,	\
+	&temp_fault[X].dev_attr.attr,		\
+	NULL					\
+}
+
+static struct attribute *pc8736x_temp_attr[][10] = {
+	TEMP_UNIT_ATTRS(0),
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2)
+};
+
+static const struct attribute_group pc8736x_temp_attr_group[] = {
+	{ .attrs = pc8736x_temp_attr[0] },
+	{ .attrs = pc8736x_temp_attr[1] },
+	{ .attrs = pc8736x_temp_attr[2] }
+};
+
+static ssize_t show_name(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+/*
+ * Device detection, registration and update
+ */
+
+static int __init pc87360_find(int sioaddr, u8 *devid,
+			       unsigned short *addresses)
+{
+	u16 val;
+	int i;
+	int nrdev; /* logical device count */
+
+	/* No superio_enter */
+
+	/* Identify device */
+	val = force_id ? force_id : superio_inb(sioaddr, DEVID);
+	switch (val) {
+	case 0xE1: /* PC87360 */
+	case 0xE8: /* PC87363 */
+	case 0xE4: /* PC87364 */
+		nrdev = 1;
+		break;
+	case 0xE5: /* PC87365 */
+	case 0xE9: /* PC87366 */
+		nrdev = 3;
+		break;
+	default:
+		superio_exit(sioaddr);
+		return -ENODEV;
+	}
+	/* Remember the device id */
+	*devid = val;
+
+	for (i = 0; i < nrdev; i++) {
+		/* select logical device */
+		superio_outb(sioaddr, DEV, logdev[i]);
+
+		val = superio_inb(sioaddr, ACT);
+		if (!(val & 0x01)) {
+			pr_info("Device 0x%02x not activated\n", logdev[i]);
+			continue;
+		}
+
+		val = (superio_inb(sioaddr, BASE) << 8)
+		    | superio_inb(sioaddr, BASE + 1);
+		if (!val) {
+			pr_info("Base address not set for device 0x%02x\n",
+				logdev[i]);
+			continue;
+		}
+
+		addresses[i] = val;
+
+		if (i == 0) { /* Fans */
+			confreg[0] = superio_inb(sioaddr, 0xF0);
+			confreg[1] = superio_inb(sioaddr, 0xF1);
+
+			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1,
+				 (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1,
+				 (confreg[0] >> 4) & 1);
+			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2,
+				 (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1,
+				 (confreg[0] >> 7) & 1);
+			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3,
+				 confreg[1] & 1, (confreg[1] >> 1) & 1,
+				 (confreg[1] >> 2) & 1);
+		} else if (i == 1) { /* Voltages */
+			/* Are we using thermistors? */
+			if (*devid == 0xE9) { /* PC87366 */
+				/*
+				 * These registers are not logical-device
+				 * specific, just that we won't need them if
+				 * we don't use the VLM device
+				 */
+				confreg[2] = superio_inb(sioaddr, 0x2B);
+				confreg[3] = superio_inb(sioaddr, 0x25);
+
+				if (confreg[2] & 0x40) {
+					pr_info("Using thermistors for temperature monitoring\n");
+				}
+				if (confreg[3] & 0xE0) {
+					pr_info("VID inputs routed (mode %u)\n",
+						confreg[3] >> 5);
+				}
+			}
+		}
+	}
+
+	superio_exit(sioaddr);
+	return 0;
+}
+
+static void pc87360_remove_files(struct device *dev)
+{
+	int i;
+
+	device_remove_file(dev, &dev_attr_name);
+	device_remove_file(dev, &dev_attr_alarms_temp);
+	for (i = 0; i < ARRAY_SIZE(pc8736x_temp_attr_group); i++)
+		sysfs_remove_group(&dev->kobj, &pc8736x_temp_attr_group[i]);
+	for (i = 0; i < ARRAY_SIZE(pc8736x_fan_attr_group); i++) {
+		sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_attr_group[i]);
+		device_remove_file(dev, &pwm[i].dev_attr);
+	}
+	sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
+	sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
+}
+
+static int pc87360_probe(struct platform_device *pdev)
+{
+	int i;
+	struct pc87360_data *data;
+	int err = 0;
+	const char *name;
+	int use_thermistors = 0;
+	struct device *dev = &pdev->dev;
+
+	data = devm_kzalloc(dev, sizeof(struct pc87360_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	switch (devid) {
+	default:
+		name = "pc87360";
+		data->fannr = 2;
+		break;
+	case 0xe8:
+		name = "pc87363";
+		data->fannr = 2;
+		break;
+	case 0xe4:
+		name = "pc87364";
+		data->fannr = 3;
+		break;
+	case 0xe5:
+		name = "pc87365";
+		data->fannr = extra_isa[0] ? 3 : 0;
+		data->innr = extra_isa[1] ? 11 : 0;
+		data->tempnr = extra_isa[2] ? 2 : 0;
+		break;
+	case 0xe9:
+		name = "pc87366";
+		data->fannr = extra_isa[0] ? 3 : 0;
+		data->innr = extra_isa[1] ? 14 : 0;
+		data->tempnr = extra_isa[2] ? 3 : 0;
+		break;
+	}
+
+	data->name = name;
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	for (i = 0; i < LDNI_MAX; i++) {
+		data->address[i] = extra_isa[i];
+		if (data->address[i]
+		 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
+					 pc87360_driver.driver.name)) {
+			dev_err(dev,
+				"Region 0x%x-0x%x already in use!\n",
+				extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
+			return -EBUSY;
+		}
+	}
+
+	/* Retrieve the fans configuration from Super-I/O space */
+	if (data->fannr)
+		data->fan_conf = confreg[0] | (confreg[1] << 8);
+
+	/*
+	 * Use the correct reference voltage
+	 * Unless both the VLM and the TMS logical devices agree to
+	 * use an external Vref, the internal one is used.
+	 */
+	if (data->innr) {
+		i = pc87360_read_value(data, LD_IN, NO_BANK,
+				       PC87365_REG_IN_CONFIG);
+		if (data->tempnr) {
+			i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
+						PC87365_REG_TEMP_CONFIG);
+		}
+		data->in_vref = (i&0x02) ? 3025 : 2966;
+		dev_dbg(dev, "Using %s reference voltage\n",
+			(i&0x02) ? "external" : "internal");
+
+		data->vid_conf = confreg[3];
+		data->vrm = vid_which_vrm();
+	}
+
+	/* Fan clock dividers may be needed before any data is read */
+	for (i = 0; i < data->fannr; i++) {
+		if (FAN_CONFIG_MONITOR(data->fan_conf, i))
+			data->fan_status[i] = pc87360_read_value(data,
+					      LD_FAN, NO_BANK,
+					      PC87360_REG_FAN_STATUS(i));
+	}
+
+	if (init > 0) {
+		if (devid == 0xe9 && data->address[1]) /* PC87366 */
+			use_thermistors = confreg[2] & 0x40;
+
+		pc87360_init_device(pdev, use_thermistors);
+	}
+
+	/* Register all-or-nothing sysfs groups */
+
+	if (data->innr) {
+		err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group);
+		if (err)
+			goto error;
+	}
+
+	if (data->innr == 14) {
+		err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group);
+		if (err)
+			goto error;
+	}
+
+	/* create device attr-files for varying sysfs groups */
+
+	if (data->tempnr) {
+		for (i = 0; i < data->tempnr; i++) {
+			err = sysfs_create_group(&dev->kobj,
+						 &pc8736x_temp_attr_group[i]);
+			if (err)
+				goto error;
+		}
+		err = device_create_file(dev, &dev_attr_alarms_temp);
+		if (err)
+			goto error;
+	}
+
+	for (i = 0; i < data->fannr; i++) {
+		if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+			err = sysfs_create_group(&dev->kobj,
+						 &pc8736x_fan_attr_group[i]);
+			if (err)
+				goto error;
+		}
+		if (FAN_CONFIG_CONTROL(data->fan_conf, i)) {
+			err = device_create_file(dev, &pwm[i].dev_attr);
+			if (err)
+				goto error;
+		}
+	}
+
+	err = device_create_file(dev, &dev_attr_name);
+	if (err)
+		goto error;
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error;
+	}
+	return 0;
+
+error:
+	pc87360_remove_files(dev);
+	return err;
+}
+
+static int pc87360_remove(struct platform_device *pdev)
+{
+	struct pc87360_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	pc87360_remove_files(&pdev->dev);
+
+	return 0;
+}
+
+/*
+ * ldi is the logical device index
+ * bank is for voltages and temperatures only
+ */
+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
+			      u8 reg)
+{
+	int res;
+
+	mutex_lock(&(data->lock));
+	if (bank != NO_BANK)
+		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
+	res = inb_p(data->address[ldi] + reg);
+	mutex_unlock(&(data->lock));
+
+	return res;
+}
+
+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
+				u8 reg, u8 value)
+{
+	mutex_lock(&(data->lock));
+	if (bank != NO_BANK)
+		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
+	outb_p(value, data->address[ldi] + reg);
+	mutex_unlock(&(data->lock));
+}
+
+/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */
+#define CHAN_CNVRTD	0x80	/* new data ready */
+#define CHAN_ENA	0x01	/* enabled channel (temp or vin) */
+#define CHAN_ALM_ENA	0x10	/* propagate to alarms-reg ?? (chk val!) */
+#define CHAN_READY	(CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */
+
+#define TEMP_OTS_OE	0x20	/* OTS Output Enable */
+#define VIN_RW1C_MASK	(CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN)   /* 0x87 */
+#define TEMP_RW1C_MASK	(VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */
+
+static void pc87360_init_device(struct platform_device *pdev,
+				int use_thermistors)
+{
+	struct pc87360_data *data = platform_get_drvdata(pdev);
+	int i, nr;
+	const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
+	const u8 init_temp[3] = { 2, 2, 1 };
+	u8 reg;
+
+	if (init >= 2 && data->innr) {
+		reg = pc87360_read_value(data, LD_IN, NO_BANK,
+					 PC87365_REG_IN_CONVRATE);
+		dev_info(&pdev->dev,
+			 "VLM conversion set to 1s period, 160us delay\n");
+		pc87360_write_value(data, LD_IN, NO_BANK,
+				    PC87365_REG_IN_CONVRATE,
+				    (reg & 0xC0) | 0x11);
+	}
+
+	nr = data->innr < 11 ? data->innr : 11;
+	for (i = 0; i < nr; i++) {
+		reg = pc87360_read_value(data, LD_IN, i,
+					 PC87365_REG_IN_STATUS);
+		dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg);
+		if (init >= init_in[i]) {
+			/* Forcibly enable voltage channel */
+			if (!(reg & CHAN_ENA)) {
+				dev_dbg(&pdev->dev, "Forcibly enabling in%d\n",
+					i);
+				pc87360_write_value(data, LD_IN, i,
+						    PC87365_REG_IN_STATUS,
+						    (reg & 0x68) | 0x87);
+			}
+		}
+	}
+
+	/*
+	 * We can't blindly trust the Super-I/O space configuration bit,
+	 * most BIOS won't set it properly
+	 */
+	dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors);
+	for (i = 11; i < data->innr; i++) {
+		reg = pc87360_read_value(data, LD_IN, i,
+					 PC87365_REG_TEMP_STATUS);
+		use_thermistors = use_thermistors || (reg & CHAN_ENA);
+		/* thermistors are temp[4-6], measured on vin[11-14] */
+		dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg);
+	}
+	dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors);
+
+	i = use_thermistors ? 2 : 0;
+	for (; i < data->tempnr; i++) {
+		reg = pc87360_read_value(data, LD_TEMP, i,
+					 PC87365_REG_TEMP_STATUS);
+		dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg);
+		if (init >= init_temp[i]) {
+			/* Forcibly enable temperature channel */
+			if (!(reg & CHAN_ENA)) {
+				dev_dbg(&pdev->dev,
+					"Forcibly enabling temp%d\n", i + 1);
+				pc87360_write_value(data, LD_TEMP, i,
+						    PC87365_REG_TEMP_STATUS,
+						    0xCF);
+			}
+		}
+	}
+
+	if (use_thermistors) {
+		for (i = 11; i < data->innr; i++) {
+			if (init >= init_in[i]) {
+				/*
+				 * The pin may already be used by thermal
+				 * diodes
+				 */
+				reg = pc87360_read_value(data, LD_TEMP,
+				      (i - 11) / 2, PC87365_REG_TEMP_STATUS);
+				if (reg & CHAN_ENA) {
+					dev_dbg(&pdev->dev,
+			"Skipping temp%d, pin already in use by temp%d\n",
+						i - 7, (i - 11) / 2);
+					continue;
+				}
+
+				/* Forcibly enable thermistor channel */
+				reg = pc87360_read_value(data, LD_IN, i,
+							 PC87365_REG_IN_STATUS);
+				if (!(reg & CHAN_ENA)) {
+					dev_dbg(&pdev->dev,
+						"Forcibly enabling temp%d\n",
+						i - 7);
+					pc87360_write_value(data, LD_IN, i,
+						PC87365_REG_TEMP_STATUS,
+						(reg & 0x60) | 0x8F);
+				}
+			}
+		}
+	}
+
+	if (data->innr) {
+		reg = pc87360_read_value(data, LD_IN, NO_BANK,
+					 PC87365_REG_IN_CONFIG);
+		dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg);
+		if (reg & CHAN_ENA) {
+			dev_dbg(&pdev->dev,
+				"Forcibly enabling monitoring (VLM)\n");
+			pc87360_write_value(data, LD_IN, NO_BANK,
+					    PC87365_REG_IN_CONFIG,
+					    reg & 0xFE);
+		}
+	}
+
+	if (data->tempnr) {
+		reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
+					 PC87365_REG_TEMP_CONFIG);
+		dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg);
+		if (reg & CHAN_ENA) {
+			dev_dbg(&pdev->dev,
+				"Forcibly enabling monitoring (TMS)\n");
+			pc87360_write_value(data, LD_TEMP, NO_BANK,
+					    PC87365_REG_TEMP_CONFIG,
+					    reg & 0xFE);
+		}
+
+		if (init >= 2) {
+			/* Chip config as documented by National Semi. */
+			pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
+			/*
+			 * We voluntarily omit the bank here, in case the
+			 * sequence itself matters. It shouldn't be a problem,
+			 * since nobody else is supposed to access the
+			 * device at that point.
+			 */
+			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
+			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
+			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
+			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);
+		}
+	}
+}
+
+static void pc87360_autodiv(struct device *dev, int nr)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	u8 old_min = data->fan_min[nr];
+
+	/* Increase clock divider if needed and possible */
+	if ((data->fan_status[nr] & 0x04) /* overflow flag */
+	 || (data->fan[nr] >= 224)) { /* next to overflow */
+		if ((data->fan_status[nr] & 0x60) != 0x60) {
+			data->fan_status[nr] += 0x20;
+			data->fan_min[nr] >>= 1;
+			data->fan[nr] >>= 1;
+			dev_dbg(dev,
+				"Increasing clock divider to %d for fan %d\n",
+				FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
+		}
+	} else {
+		/* Decrease clock divider if possible */
+		while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */
+		 && data->fan[nr] < 85 /* bad accuracy */
+		 && (data->fan_status[nr] & 0x60) != 0x00) {
+			data->fan_status[nr] -= 0x20;
+			data->fan_min[nr] <<= 1;
+			data->fan[nr] <<= 1;
+			dev_dbg(dev,
+				"Decreasing clock divider to %d for fan %d\n",
+				FAN_DIV_FROM_REG(data->fan_status[nr]),
+				nr + 1);
+		}
+	}
+
+	/* Write new fan min if it changed */
+	if (old_min != data->fan_min[nr]) {
+		pc87360_write_value(data, LD_FAN, NO_BANK,
+				    PC87360_REG_FAN_MIN(nr),
+				    data->fan_min[nr]);
+	}
+}
+
+static struct pc87360_data *pc87360_update_device(struct device *dev)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	u8 i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+		dev_dbg(dev, "Data update\n");
+
+		/* Fans */
+		for (i = 0; i < data->fannr; i++) {
+			if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+				data->fan_status[i] =
+					pc87360_read_value(data, LD_FAN,
+					NO_BANK, PC87360_REG_FAN_STATUS(i));
+				data->fan[i] = pc87360_read_value(data, LD_FAN,
+					       NO_BANK, PC87360_REG_FAN(i));
+				data->fan_min[i] = pc87360_read_value(data,
+						   LD_FAN, NO_BANK,
+						   PC87360_REG_FAN_MIN(i));
+				/* Change clock divider if needed */
+				pc87360_autodiv(dev, i);
+				/* Clear bits and write new divider */
+				pc87360_write_value(data, LD_FAN, NO_BANK,
+						    PC87360_REG_FAN_STATUS(i),
+						    data->fan_status[i]);
+			}
+			if (FAN_CONFIG_CONTROL(data->fan_conf, i))
+				data->pwm[i] = pc87360_read_value(data, LD_FAN,
+					       NO_BANK, PC87360_REG_PWM(i));
+		}
+
+		/* Voltages */
+		for (i = 0; i < data->innr; i++) {
+			data->in_status[i] = pc87360_read_value(data, LD_IN, i,
+					     PC87365_REG_IN_STATUS);
+			/* Clear bits */
+			pc87360_write_value(data, LD_IN, i,
+					    PC87365_REG_IN_STATUS,
+					    data->in_status[i]);
+			if ((data->in_status[i] & CHAN_READY) == CHAN_READY) {
+				data->in[i] = pc87360_read_value(data, LD_IN,
+					      i, PC87365_REG_IN);
+			}
+			if (data->in_status[i] & CHAN_ENA) {
+				data->in_min[i] = pc87360_read_value(data,
+						  LD_IN, i,
+						  PC87365_REG_IN_MIN);
+				data->in_max[i] = pc87360_read_value(data,
+						  LD_IN, i,
+						  PC87365_REG_IN_MAX);
+				if (i >= 11)
+					data->in_crit[i-11] =
+						pc87360_read_value(data, LD_IN,
+						i, PC87365_REG_TEMP_CRIT);
+			}
+		}
+		if (data->innr) {
+			data->in_alarms = pc87360_read_value(data, LD_IN,
+					  NO_BANK, PC87365_REG_IN_ALARMS1)
+					| ((pc87360_read_value(data, LD_IN,
+					    NO_BANK, PC87365_REG_IN_ALARMS2)
+					    & 0x07) << 8);
+			data->vid = (data->vid_conf & 0xE0) ?
+				    pc87360_read_value(data, LD_IN,
+				    NO_BANK, PC87365_REG_VID) : 0x1F;
+		}
+
+		/* Temperatures */
+		for (i = 0; i < data->tempnr; i++) {
+			data->temp_status[i] = pc87360_read_value(data,
+					       LD_TEMP, i,
+					       PC87365_REG_TEMP_STATUS);
+			/* Clear bits */
+			pc87360_write_value(data, LD_TEMP, i,
+					    PC87365_REG_TEMP_STATUS,
+					    data->temp_status[i]);
+			if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) {
+				data->temp[i] = pc87360_read_value(data,
+						LD_TEMP, i,
+						PC87365_REG_TEMP);
+			}
+			if (data->temp_status[i] & CHAN_ENA) {
+				data->temp_min[i] = pc87360_read_value(data,
+						    LD_TEMP, i,
+						    PC87365_REG_TEMP_MIN);
+				data->temp_max[i] = pc87360_read_value(data,
+						    LD_TEMP, i,
+						    PC87365_REG_TEMP_MAX);
+				data->temp_crit[i] = pc87360_read_value(data,
+						     LD_TEMP, i,
+						     PC87365_REG_TEMP_CRIT);
+			}
+		}
+		if (data->tempnr) {
+			data->temp_alarms = pc87360_read_value(data, LD_TEMP,
+					    NO_BANK, PC87365_REG_TEMP_ALARMS)
+					    & 0x3F;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int __init pc87360_device_add(unsigned short address)
+{
+	struct resource res[3];
+	int err, i, res_count;
+
+	pdev = platform_device_alloc("pc87360", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	memset(res, 0, 3 * sizeof(struct resource));
+	res_count = 0;
+	for (i = 0; i < 3; i++) {
+		if (!extra_isa[i])
+			continue;
+		res[res_count].start = extra_isa[i];
+		res[res_count].end = extra_isa[i] + PC87360_EXTENT - 1;
+		res[res_count].name = "pc87360",
+		res[res_count].flags = IORESOURCE_IO,
+
+		err = acpi_check_resource_conflict(&res[res_count]);
+		if (err)
+			goto exit_device_put;
+
+		res_count++;
+	}
+
+	err = platform_device_add_resources(pdev, res, res_count);
+	if (err) {
+		pr_err("Device resources addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init pc87360_init(void)
+{
+	int err, i;
+	unsigned short address = 0;
+
+	if (pc87360_find(0x2e, &devid, extra_isa)
+	 && pc87360_find(0x4e, &devid, extra_isa)) {
+		pr_warn("PC8736x not detected, module not inserted\n");
+		return -ENODEV;
+	}
+
+	/* Arbitrarily pick one of the addresses */
+	for (i = 0; i < 3; i++) {
+		if (extra_isa[i] != 0x0000) {
+			address = extra_isa[i];
+			break;
+		}
+	}
+
+	if (address == 0x0000) {
+		pr_warn("No active logical device, module not inserted\n");
+		return -ENODEV;
+	}
+
+	err = platform_driver_register(&pc87360_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = pc87360_device_add(address);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+ exit_driver:
+	platform_driver_unregister(&pc87360_driver);
+ exit:
+	return err;
+}
+
+static void __exit pc87360_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&pc87360_driver);
+}
+
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("PC8736x hardware monitor");
+MODULE_LICENSE("GPL");
+
+module_init(pc87360_init);
+module_exit(pc87360_exit);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
new file mode 100644
index 0000000..cb9fdd3
--- /dev/null
+++ b/drivers/hwmon/pc87427.c
@@ -0,0 +1,1352 @@
+/*
+ *  pc87427.c - hardware monitoring driver for the
+ *              National Semiconductor PC87427 Super-I/O chip
+ *  Copyright (C) 2006, 2008, 2010  Jean Delvare <jdelvare@suse.de>
+ *
+ *  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.
+ *
+ *  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.
+ *
+ *  Supports the following chips:
+ *
+ *  Chip        #vin    #fan    #pwm    #temp   devid
+ *  PC87427     -       8       4       6       0xF2
+ *
+ *  This driver assumes that no more than one chip is present.
+ *  Only fans are fully supported so far. Temperatures are in read-only
+ *  mode, and voltages aren't supported at all.
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "pc87427"
+
+/*
+ * The lock mutex protects both the I/O accesses (needed because the
+ * device is using banked registers) and the register cache (needed to keep
+ * the data in the registers and the cache in sync at any time).
+ */
+struct pc87427_data {
+	struct device *hwmon_dev;
+	struct mutex lock;
+	int address[2];
+	const char *name;
+
+	unsigned long last_updated;	/* in jiffies */
+	u8 fan_enabled;			/* bit vector */
+	u16 fan[8];			/* register values */
+	u16 fan_min[8];			/* register values */
+	u8 fan_status[8];		/* register values */
+
+	u8 pwm_enabled;			/* bit vector */
+	u8 pwm_auto_ok;			/* bit vector */
+	u8 pwm_enable[4];		/* register values */
+	u8 pwm[4];			/* register values */
+
+	u8 temp_enabled;		/* bit vector */
+	s16 temp[6];			/* register values */
+	s8 temp_min[6];			/* register values */
+	s8 temp_max[6];			/* register values */
+	s8 temp_crit[6];		/* register values */
+	u8 temp_status[6];		/* register values */
+	u8 temp_type[6];		/* register values */
+};
+
+struct pc87427_sio_data {
+	unsigned short address[2];
+	u8 has_fanin;
+	u8 has_fanout;
+};
+
+/*
+ * Super-I/O registers and operations
+ */
+
+#define SIOREG_LDSEL	0x07	/* Logical device select */
+#define SIOREG_DEVID	0x20	/* Device ID */
+#define SIOREG_CF2	0x22	/* Configuration 2 */
+#define SIOREG_CF3	0x23	/* Configuration 3 */
+#define SIOREG_CF4	0x24	/* Configuration 4 */
+#define SIOREG_CF5	0x25	/* Configuration 5 */
+#define SIOREG_CFB	0x2B	/* Configuration B */
+#define SIOREG_CFC	0x2C	/* Configuration C */
+#define SIOREG_CFD	0x2D	/* Configuration D */
+#define SIOREG_ACT	0x30	/* Device activation */
+#define SIOREG_MAP	0x50	/* I/O or memory mapping */
+#define SIOREG_IOBASE	0x60	/* I/O base address */
+
+static const u8 logdev[2] = { 0x09, 0x14 };
+static const char *logdev_str[2] = { DRVNAME " FMC", DRVNAME " HMC" };
+#define LD_FAN		0
+#define LD_IN		1
+#define LD_TEMP		1
+
+static inline void superio_outb(int sioaddr, int reg, int val)
+{
+	outb(reg, sioaddr);
+	outb(val, sioaddr + 1);
+}
+
+static inline int superio_inb(int sioaddr, int reg)
+{
+	outb(reg, sioaddr);
+	return inb(sioaddr + 1);
+}
+
+static inline void superio_exit(int sioaddr)
+{
+	outb(0x02, sioaddr);
+	outb(0x02, sioaddr + 1);
+}
+
+/*
+ * Logical devices
+ */
+
+#define REGION_LENGTH		32
+#define PC87427_REG_BANK	0x0f
+#define BANK_FM(nr)		(nr)
+#define BANK_FT(nr)		(0x08 + (nr))
+#define BANK_FC(nr)		(0x10 + (nr) * 2)
+#define BANK_TM(nr)		(nr)
+#define BANK_VM(nr)		(0x08 + (nr))
+
+/*
+ * I/O access functions
+ */
+
+/* ldi is the logical device index */
+static inline int pc87427_read8(struct pc87427_data *data, u8 ldi, u8 reg)
+{
+	return inb(data->address[ldi] + reg);
+}
+
+/* Must be called with data->lock held, except during init */
+static inline int pc87427_read8_bank(struct pc87427_data *data, u8 ldi,
+				     u8 bank, u8 reg)
+{
+	outb(bank, data->address[ldi] + PC87427_REG_BANK);
+	return inb(data->address[ldi] + reg);
+}
+
+/* Must be called with data->lock held, except during init */
+static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi,
+				       u8 bank, u8 reg, u8 value)
+{
+	outb(bank, data->address[ldi] + PC87427_REG_BANK);
+	outb(value, data->address[ldi] + reg);
+}
+
+/*
+ * Fan registers and conversions
+ */
+
+/* fan data registers are 16-bit wide */
+#define PC87427_REG_FAN			0x12
+#define PC87427_REG_FAN_MIN		0x14
+#define PC87427_REG_FAN_STATUS		0x10
+
+#define FAN_STATUS_STALL		(1 << 3)
+#define FAN_STATUS_LOSPD		(1 << 1)
+#define FAN_STATUS_MONEN		(1 << 0)
+
+/*
+ * Dedicated function to read all registers related to a given fan input.
+ * This saves us quite a few locks and bank selections.
+ * Must be called with data->lock held.
+ * nr is from 0 to 7
+ */
+static void pc87427_readall_fan(struct pc87427_data *data, u8 nr)
+{
+	int iobase = data->address[LD_FAN];
+
+	outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
+	data->fan[nr] = inw(iobase + PC87427_REG_FAN);
+	data->fan_min[nr] = inw(iobase + PC87427_REG_FAN_MIN);
+	data->fan_status[nr] = inb(iobase + PC87427_REG_FAN_STATUS);
+	/* Clear fan alarm bits */
+	outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS);
+}
+
+/*
+ * The 2 LSB of fan speed registers are used for something different.
+ * The actual 2 LSB of the measurements are not available.
+ */
+static inline unsigned long fan_from_reg(u16 reg)
+{
+	reg &= 0xfffc;
+	if (reg == 0x0000 || reg == 0xfffc)
+		return 0;
+	return 5400000UL / reg;
+}
+
+/* The 2 LSB of the fan speed limit registers are not significant. */
+static inline u16 fan_to_reg(unsigned long val)
+{
+	if (val < 83UL)
+		return 0xffff;
+	if (val >= 1350000UL)
+		return 0x0004;
+	return ((1350000UL + val / 2) / val) << 2;
+}
+
+/*
+ * PWM registers and conversions
+ */
+
+#define PC87427_REG_PWM_ENABLE		0x10
+#define PC87427_REG_PWM_DUTY		0x12
+
+#define PWM_ENABLE_MODE_MASK		(7 << 4)
+#define PWM_ENABLE_CTLEN		(1 << 0)
+
+#define PWM_MODE_MANUAL			(0 << 4)
+#define PWM_MODE_AUTO			(1 << 4)
+#define PWM_MODE_OFF			(2 << 4)
+#define PWM_MODE_ON			(7 << 4)
+
+/*
+ * Dedicated function to read all registers related to a given PWM output.
+ * This saves us quite a few locks and bank selections.
+ * Must be called with data->lock held.
+ * nr is from 0 to 3
+ */
+static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr)
+{
+	int iobase = data->address[LD_FAN];
+
+	outb(BANK_FC(nr), iobase + PC87427_REG_BANK);
+	data->pwm_enable[nr] = inb(iobase + PC87427_REG_PWM_ENABLE);
+	data->pwm[nr] = inb(iobase + PC87427_REG_PWM_DUTY);
+}
+
+static inline int pwm_enable_from_reg(u8 reg)
+{
+	switch (reg & PWM_ENABLE_MODE_MASK) {
+	case PWM_MODE_ON:
+		return 0;
+	case PWM_MODE_MANUAL:
+	case PWM_MODE_OFF:
+		return 1;
+	case PWM_MODE_AUTO:
+		return 2;
+	default:
+		return -EPROTO;
+	}
+}
+
+static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval)
+{
+	switch (val) {
+	default:
+		return PWM_MODE_ON;
+	case 1:
+		return pwmval ? PWM_MODE_MANUAL : PWM_MODE_OFF;
+	case 2:
+		return PWM_MODE_AUTO;
+	}
+}
+
+/*
+ * Temperature registers and conversions
+ */
+
+#define PC87427_REG_TEMP_STATUS		0x10
+#define PC87427_REG_TEMP		0x14
+#define PC87427_REG_TEMP_MAX		0x18
+#define PC87427_REG_TEMP_MIN		0x19
+#define PC87427_REG_TEMP_CRIT		0x1a
+#define PC87427_REG_TEMP_TYPE		0x1d
+
+#define TEMP_STATUS_CHANEN		(1 << 0)
+#define TEMP_STATUS_LOWFLG		(1 << 1)
+#define TEMP_STATUS_HIGHFLG		(1 << 2)
+#define TEMP_STATUS_CRITFLG		(1 << 3)
+#define TEMP_STATUS_SENSERR		(1 << 5)
+#define TEMP_TYPE_MASK			(3 << 5)
+
+#define TEMP_TYPE_THERMISTOR		(1 << 5)
+#define TEMP_TYPE_REMOTE_DIODE		(2 << 5)
+#define TEMP_TYPE_LOCAL_DIODE		(3 << 5)
+
+/*
+ * Dedicated function to read all registers related to a given temperature
+ * input. This saves us quite a few locks and bank selections.
+ * Must be called with data->lock held.
+ * nr is from 0 to 5
+ */
+static void pc87427_readall_temp(struct pc87427_data *data, u8 nr)
+{
+	int iobase = data->address[LD_TEMP];
+
+	outb(BANK_TM(nr), iobase + PC87427_REG_BANK);
+	data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP));
+	data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX);
+	data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN);
+	data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT);
+	data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE);
+	data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS);
+	/* Clear fan alarm bits */
+	outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS);
+}
+
+static inline unsigned int temp_type_from_reg(u8 reg)
+{
+	switch (reg & TEMP_TYPE_MASK) {
+	case TEMP_TYPE_THERMISTOR:
+		return 4;
+	case TEMP_TYPE_REMOTE_DIODE:
+	case TEMP_TYPE_LOCAL_DIODE:
+		return 3;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * We assume 8-bit thermal sensors; 9-bit thermal sensors are possible
+ * too, but I have no idea how to figure out when they are used.
+ */
+static inline long temp_from_reg(s16 reg)
+{
+	return reg * 1000 / 256;
+}
+
+static inline long temp_from_reg8(s8 reg)
+{
+	return reg * 1000;
+}
+
+/*
+ * Data interface
+ */
+
+static struct pc87427_data *pc87427_update_device(struct device *dev)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->lock);
+	if (!time_after(jiffies, data->last_updated + HZ)
+	 && data->last_updated)
+		goto done;
+
+	/* Fans */
+	for (i = 0; i < 8; i++) {
+		if (!(data->fan_enabled & (1 << i)))
+			continue;
+		pc87427_readall_fan(data, i);
+	}
+
+	/* PWM outputs */
+	for (i = 0; i < 4; i++) {
+		if (!(data->pwm_enabled & (1 << i)))
+			continue;
+		pc87427_readall_pwm(data, i);
+	}
+
+	/* Temperature channels */
+	for (i = 0; i < 6; i++) {
+		if (!(data->temp_enabled & (1 << i)))
+			continue;
+		pc87427_readall_temp(data, i);
+	}
+
+	data->last_updated = jiffies;
+
+done:
+	mutex_unlock(&data->lock);
+	return data;
+}
+
+static ssize_t show_fan_input(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr]));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute
+			    *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr]));
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->fan_status[nr]
+				       & FAN_STATUS_LOSPD));
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->fan_status[nr]
+				       & FAN_STATUS_STALL));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+	unsigned long val;
+	int iobase = data->address[LD_FAN];
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
+	/*
+	 * The low speed limit registers are read-only while monitoring
+	 * is enabled, so we have to disable monitoring, then change the
+	 * limit, and finally enable monitoring again.
+	 */
+	outb(0, iobase + PC87427_REG_FAN_STATUS);
+	data->fan_min[nr] = fan_to_reg(val);
+	outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN);
+	outb(FAN_STATUS_MONEN, iobase + PC87427_REG_FAN_STATUS);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan_input, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, set_fan_min, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_fan_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_fan_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_fan_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_fan_alarm, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, show_fan_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, show_fan_fault, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, show_fan_fault, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, show_fan_fault, NULL, 7);
+
+static struct attribute *pc87427_attributes_fan[8][5] = {
+	{
+		&sensor_dev_attr_fan1_input.dev_attr.attr,
+		&sensor_dev_attr_fan1_min.dev_attr.attr,
+		&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan1_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan2_input.dev_attr.attr,
+		&sensor_dev_attr_fan2_min.dev_attr.attr,
+		&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan2_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan3_input.dev_attr.attr,
+		&sensor_dev_attr_fan3_min.dev_attr.attr,
+		&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan3_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan4_input.dev_attr.attr,
+		&sensor_dev_attr_fan4_min.dev_attr.attr,
+		&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan4_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan5_input.dev_attr.attr,
+		&sensor_dev_attr_fan5_min.dev_attr.attr,
+		&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan5_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan6_input.dev_attr.attr,
+		&sensor_dev_attr_fan6_min.dev_attr.attr,
+		&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan6_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan7_input.dev_attr.attr,
+		&sensor_dev_attr_fan7_min.dev_attr.attr,
+		&sensor_dev_attr_fan7_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan7_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan8_input.dev_attr.attr,
+		&sensor_dev_attr_fan8_min.dev_attr.attr,
+		&sensor_dev_attr_fan8_alarm.dev_attr.attr,
+		&sensor_dev_attr_fan8_fault.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group pc87427_group_fan[8] = {
+	{ .attrs = pc87427_attributes_fan[0] },
+	{ .attrs = pc87427_attributes_fan[1] },
+	{ .attrs = pc87427_attributes_fan[2] },
+	{ .attrs = pc87427_attributes_fan[3] },
+	{ .attrs = pc87427_attributes_fan[4] },
+	{ .attrs = pc87427_attributes_fan[5] },
+	{ .attrs = pc87427_attributes_fan[6] },
+	{ .attrs = pc87427_attributes_fan[7] },
+};
+
+/*
+ * Must be called with data->lock held and pc87427_readall_pwm() freshly
+ * called
+ */
+static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode)
+{
+	int iobase = data->address[LD_FAN];
+	data->pwm_enable[nr] &= ~PWM_ENABLE_MODE_MASK;
+	data->pwm_enable[nr] |= mode;
+	outb(data->pwm_enable[nr], iobase + PC87427_REG_PWM_ENABLE);
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+	int pwm_enable;
+
+	pwm_enable = pwm_enable_from_reg(data->pwm_enable[nr]);
+	if (pwm_enable < 0)
+		return pwm_enable;
+	return sprintf(buf, "%d\n", pwm_enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+			      *devattr, const char *buf, size_t count)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0 || val > 2)
+		return -EINVAL;
+	/* Can't go to automatic mode if it isn't configured */
+	if (val == 2 && !(data->pwm_auto_ok & (1 << nr)))
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	pc87427_readall_pwm(data, nr);
+	update_pwm_enable(data, nr, pwm_enable_to_reg(val, data->pwm[nr]));
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute
+			*devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", (int)data->pwm[nr]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute
+		       *devattr, const char *buf, size_t count)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+	unsigned long val;
+	int iobase = data->address[LD_FAN];
+	u8 mode;
+
+	if (kstrtoul(buf, 10, &val) < 0 || val > 0xff)
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	pc87427_readall_pwm(data, nr);
+	mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
+	if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
+		dev_notice(dev,
+			   "Can't set PWM%d duty cycle while not in manual mode\n",
+			   nr + 1);
+		mutex_unlock(&data->lock);
+		return -EPERM;
+	}
+
+	/* We may have to change the mode */
+	if (mode == PWM_MODE_MANUAL && val == 0) {
+		/* Transition from Manual to Off */
+		update_pwm_enable(data, nr, PWM_MODE_OFF);
+		mode = PWM_MODE_OFF;
+		dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1,
+			"manual", "off");
+	} else if (mode == PWM_MODE_OFF && val != 0) {
+		/* Transition from Off to Manual */
+		update_pwm_enable(data, nr, PWM_MODE_MANUAL);
+		mode = PWM_MODE_MANUAL;
+		dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1,
+			"off", "manual");
+	}
+
+	data->pwm[nr] = val;
+	if (mode == PWM_MODE_MANUAL)
+		outb(val, iobase + PC87427_REG_PWM_DUTY);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+			  show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+			  show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+			  show_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO,
+			  show_pwm_enable, set_pwm_enable, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static struct attribute *pc87427_attributes_pwm[4][3] = {
+	{
+		&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+		&sensor_dev_attr_pwm1.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+		&sensor_dev_attr_pwm2.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+		&sensor_dev_attr_pwm3.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_pwm4_enable.dev_attr.attr,
+		&sensor_dev_attr_pwm4.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group pc87427_group_pwm[4] = {
+	{ .attrs = pc87427_attributes_pwm[0] },
+	{ .attrs = pc87427_attributes_pwm[1] },
+	{ .attrs = pc87427_attributes_pwm[2] },
+	{ .attrs = pc87427_attributes_pwm[3] },
+};
+
+static ssize_t show_temp_input(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr]));
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr]));
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr]));
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+			      *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr]));
+}
+
+static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute
+				   *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->temp_status[nr]
+				       & TEMP_STATUS_LOWFLG));
+}
+
+static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute
+				   *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->temp_status[nr]
+				       & TEMP_STATUS_HIGHFLG));
+}
+
+static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute
+				   *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->temp_status[nr]
+				       & TEMP_STATUS_CRITFLG));
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+			       *devattr, char *buf)
+{
+	struct pc87427_data *data = pc87427_update_device(dev);
+	int nr = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", !!(data->temp_status[nr]
+				       & TEMP_STATUS_SENSERR));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO,
+			  show_temp_min_alarm, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO,
+			  show_temp_max_alarm, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO,
+			  show_temp_crit_alarm, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
+
+static struct attribute *pc87427_attributes_temp[6][10] = {
+	{
+		&sensor_dev_attr_temp1_input.dev_attr.attr,
+		&sensor_dev_attr_temp1_min.dev_attr.attr,
+		&sensor_dev_attr_temp1_max.dev_attr.attr,
+		&sensor_dev_attr_temp1_crit.dev_attr.attr,
+		&sensor_dev_attr_temp1_type.dev_attr.attr,
+		&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp1_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp2_input.dev_attr.attr,
+		&sensor_dev_attr_temp2_min.dev_attr.attr,
+		&sensor_dev_attr_temp2_max.dev_attr.attr,
+		&sensor_dev_attr_temp2_crit.dev_attr.attr,
+		&sensor_dev_attr_temp2_type.dev_attr.attr,
+		&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp2_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp3_input.dev_attr.attr,
+		&sensor_dev_attr_temp3_min.dev_attr.attr,
+		&sensor_dev_attr_temp3_max.dev_attr.attr,
+		&sensor_dev_attr_temp3_crit.dev_attr.attr,
+		&sensor_dev_attr_temp3_type.dev_attr.attr,
+		&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp3_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp4_input.dev_attr.attr,
+		&sensor_dev_attr_temp4_min.dev_attr.attr,
+		&sensor_dev_attr_temp4_max.dev_attr.attr,
+		&sensor_dev_attr_temp4_crit.dev_attr.attr,
+		&sensor_dev_attr_temp4_type.dev_attr.attr,
+		&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp4_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp5_input.dev_attr.attr,
+		&sensor_dev_attr_temp5_min.dev_attr.attr,
+		&sensor_dev_attr_temp5_max.dev_attr.attr,
+		&sensor_dev_attr_temp5_crit.dev_attr.attr,
+		&sensor_dev_attr_temp5_type.dev_attr.attr,
+		&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp5_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp6_input.dev_attr.attr,
+		&sensor_dev_attr_temp6_min.dev_attr.attr,
+		&sensor_dev_attr_temp6_max.dev_attr.attr,
+		&sensor_dev_attr_temp6_crit.dev_attr.attr,
+		&sensor_dev_attr_temp6_type.dev_attr.attr,
+		&sensor_dev_attr_temp6_min_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp6_fault.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group pc87427_group_temp[6] = {
+	{ .attrs = pc87427_attributes_temp[0] },
+	{ .attrs = pc87427_attributes_temp[1] },
+	{ .attrs = pc87427_attributes_temp[2] },
+	{ .attrs = pc87427_attributes_temp[3] },
+	{ .attrs = pc87427_attributes_temp[4] },
+	{ .attrs = pc87427_attributes_temp[5] },
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+
+/*
+ * Device detection, attach and detach
+ */
+
+static int pc87427_request_regions(struct platform_device *pdev,
+					     int count)
+{
+	struct resource *res;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		res = platform_get_resource(pdev, IORESOURCE_IO, i);
+		if (!res) {
+			dev_err(&pdev->dev, "Missing resource #%d\n", i);
+			return -ENOENT;
+		}
+		if (!devm_request_region(&pdev->dev, res->start,
+					 resource_size(res), DRVNAME)) {
+			dev_err(&pdev->dev,
+				"Failed to request region 0x%lx-0x%lx\n",
+				(unsigned long)res->start,
+				(unsigned long)res->end);
+			return -EBUSY;
+		}
+	}
+	return 0;
+}
+
+static void pc87427_init_device(struct device *dev)
+{
+	struct pc87427_sio_data *sio_data = dev_get_platdata(dev);
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int i;
+	u8 reg;
+
+	/* The FMC module should be ready */
+	reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);
+	if (!(reg & 0x80))
+		dev_warn(dev, "%s module not ready!\n", "FMC");
+
+	/* Check which fans are enabled */
+	for (i = 0; i < 8; i++) {
+		if (!(sio_data->has_fanin & (1 << i)))	/* Not wired */
+			continue;
+		reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i),
+					 PC87427_REG_FAN_STATUS);
+		if (reg & FAN_STATUS_MONEN)
+			data->fan_enabled |= (1 << i);
+	}
+
+	if (!data->fan_enabled) {
+		dev_dbg(dev, "Enabling monitoring of all fans\n");
+		for (i = 0; i < 8; i++) {
+			if (!(sio_data->has_fanin & (1 << i)))	/* Not wired */
+				continue;
+			pc87427_write8_bank(data, LD_FAN, BANK_FM(i),
+					    PC87427_REG_FAN_STATUS,
+					    FAN_STATUS_MONEN);
+		}
+		data->fan_enabled = sio_data->has_fanin;
+	}
+
+	/* Check which PWM outputs are enabled */
+	for (i = 0; i < 4; i++) {
+		if (!(sio_data->has_fanout & (1 << i)))	/* Not wired */
+			continue;
+		reg = pc87427_read8_bank(data, LD_FAN, BANK_FC(i),
+					 PC87427_REG_PWM_ENABLE);
+		if (reg & PWM_ENABLE_CTLEN)
+			data->pwm_enabled |= (1 << i);
+
+		/*
+		 * We don't expose an interface to reconfigure the automatic
+		 * fan control mode, so only allow to return to this mode if
+		 * it was originally set.
+		 */
+		if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) {
+			dev_dbg(dev, "PWM%d is in automatic control mode\n",
+				i + 1);
+			data->pwm_auto_ok |= (1 << i);
+		}
+	}
+
+	/* The HMC module should be ready */
+	reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK);
+	if (!(reg & 0x80))
+		dev_warn(dev, "%s module not ready!\n", "HMC");
+
+	/* Check which temperature channels are enabled */
+	for (i = 0; i < 6; i++) {
+		reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i),
+					 PC87427_REG_TEMP_STATUS);
+		if (reg & TEMP_STATUS_CHANEN)
+			data->temp_enabled |= (1 << i);
+	}
+}
+
+static void pc87427_remove_files(struct device *dev)
+{
+	struct pc87427_data *data = dev_get_drvdata(dev);
+	int i;
+
+	device_remove_file(dev, &dev_attr_name);
+	for (i = 0; i < 8; i++) {
+		if (!(data->fan_enabled & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &pc87427_group_fan[i]);
+	}
+	for (i = 0; i < 4; i++) {
+		if (!(data->pwm_enabled & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &pc87427_group_pwm[i]);
+	}
+	for (i = 0; i < 6; i++) {
+		if (!(data->temp_enabled & (1 << i)))
+			continue;
+		sysfs_remove_group(&dev->kobj, &pc87427_group_temp[i]);
+	}
+}
+
+static int pc87427_probe(struct platform_device *pdev)
+{
+	struct pc87427_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	struct pc87427_data *data;
+	int i, err, res_count;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->address[0] = sio_data->address[0];
+	data->address[1] = sio_data->address[1];
+	res_count = (data->address[0] != 0) + (data->address[1] != 0);
+
+	err = pc87427_request_regions(pdev, res_count);
+	if (err)
+		return err;
+
+	mutex_init(&data->lock);
+	data->name = "pc87427";
+	platform_set_drvdata(pdev, data);
+	pc87427_init_device(&pdev->dev);
+
+	/* Register sysfs hooks */
+	err = device_create_file(&pdev->dev, &dev_attr_name);
+	if (err)
+		return err;
+	for (i = 0; i < 8; i++) {
+		if (!(data->fan_enabled & (1 << i)))
+			continue;
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &pc87427_group_fan[i]);
+		if (err)
+			goto exit_remove_files;
+	}
+	for (i = 0; i < 4; i++) {
+		if (!(data->pwm_enabled & (1 << i)))
+			continue;
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &pc87427_group_pwm[i]);
+		if (err)
+			goto exit_remove_files;
+	}
+	for (i = 0; i < 6; i++) {
+		if (!(data->temp_enabled & (1 << i)))
+			continue;
+		err = sysfs_create_group(&pdev->dev.kobj,
+					 &pc87427_group_temp[i]);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	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_remove_files;
+	}
+
+	return 0;
+
+exit_remove_files:
+	pc87427_remove_files(&pdev->dev);
+	return err;
+}
+
+static int pc87427_remove(struct platform_device *pdev)
+{
+	struct pc87427_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	pc87427_remove_files(&pdev->dev);
+
+	return 0;
+}
+
+
+static struct platform_driver pc87427_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= pc87427_probe,
+	.remove		= pc87427_remove,
+};
+
+static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data)
+{
+	struct resource res[2] = {
+		{ .flags	= IORESOURCE_IO },
+		{ .flags	= IORESOURCE_IO },
+	};
+	int err, i, res_count;
+
+	res_count = 0;
+	for (i = 0; i < 2; i++) {
+		if (!sio_data->address[i])
+			continue;
+		res[res_count].start = sio_data->address[i];
+		res[res_count].end = sio_data->address[i] + REGION_LENGTH - 1;
+		res[res_count].name = logdev_str[i];
+
+		err = acpi_check_resource_conflict(&res[res_count]);
+		if (err)
+			goto exit;
+
+		res_count++;
+	}
+
+	pdev = platform_device_alloc(DRVNAME, res[0].start);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, res, res_count);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct pc87427_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
+{
+	u16 val;
+	u8 cfg, cfg_b;
+	int i, err = 0;
+
+	/* Identify device */
+	val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID);
+	if (val != 0xf2) {	/* PC87427 */
+		err = -ENODEV;
+		goto exit;
+	}
+
+	for (i = 0; i < 2; i++) {
+		sio_data->address[i] = 0;
+		/* Select logical device */
+		superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]);
+
+		val = superio_inb(sioaddr, SIOREG_ACT);
+		if (!(val & 0x01)) {
+			pr_info("Logical device 0x%02x not activated\n",
+				logdev[i]);
+			continue;
+		}
+
+		val = superio_inb(sioaddr, SIOREG_MAP);
+		if (val & 0x01) {
+			pr_warn("Logical device 0x%02x is memory-mapped, can't use\n",
+				logdev[i]);
+			continue;
+		}
+
+		val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
+		    | superio_inb(sioaddr, SIOREG_IOBASE + 1);
+		if (!val) {
+			pr_info("I/O base address not set for logical device 0x%02x\n",
+				logdev[i]);
+			continue;
+		}
+		sio_data->address[i] = val;
+	}
+
+	/* No point in loading the driver if everything is disabled */
+	if (!sio_data->address[0] && !sio_data->address[1]) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* Check which fan inputs are wired */
+	sio_data->has_fanin = (1 << 2) | (1 << 3);	/* FANIN2, FANIN3 */
+
+	cfg = superio_inb(sioaddr, SIOREG_CF2);
+	if (!(cfg & (1 << 3)))
+		sio_data->has_fanin |= (1 << 0);	/* FANIN0 */
+	if (!(cfg & (1 << 2)))
+		sio_data->has_fanin |= (1 << 4);	/* FANIN4 */
+
+	cfg = superio_inb(sioaddr, SIOREG_CFD);
+	if (!(cfg & (1 << 0)))
+		sio_data->has_fanin |= (1 << 1);	/* FANIN1 */
+
+	cfg = superio_inb(sioaddr, SIOREG_CF4);
+	if (!(cfg & (1 << 0)))
+		sio_data->has_fanin |= (1 << 7);	/* FANIN7 */
+	cfg_b = superio_inb(sioaddr, SIOREG_CFB);
+	if (!(cfg & (1 << 1)) && (cfg_b & (1 << 3)))
+		sio_data->has_fanin |= (1 << 5);	/* FANIN5 */
+	cfg = superio_inb(sioaddr, SIOREG_CF3);
+	if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5)))
+		sio_data->has_fanin |= (1 << 6);	/* FANIN6 */
+
+	/* Check which fan outputs are wired */
+	sio_data->has_fanout = (1 << 0);		/* FANOUT0 */
+	if (cfg_b & (1 << 0))
+		sio_data->has_fanout |= (1 << 3);	/* FANOUT3 */
+
+	cfg = superio_inb(sioaddr, SIOREG_CFC);
+	if (!(cfg & (1 << 4))) {
+		if (cfg_b & (1 << 1))
+			sio_data->has_fanout |= (1 << 1); /* FANOUT1 */
+		if (cfg_b & (1 << 2))
+			sio_data->has_fanout |= (1 << 2); /* FANOUT2 */
+	}
+
+	/* FANOUT1 and FANOUT2 can each be routed to 2 different pins */
+	cfg = superio_inb(sioaddr, SIOREG_CF5);
+	if (cfg & (1 << 6))
+		sio_data->has_fanout |= (1 << 1);	/* FANOUT1 */
+	if (cfg & (1 << 5))
+		sio_data->has_fanout |= (1 << 2);	/* FANOUT2 */
+
+exit:
+	superio_exit(sioaddr);
+	return err;
+}
+
+static int __init pc87427_init(void)
+{
+	int err;
+	struct pc87427_sio_data sio_data;
+
+	if (pc87427_find(0x2e, &sio_data)
+	 && pc87427_find(0x4e, &sio_data))
+		return -ENODEV;
+
+	err = platform_driver_register(&pc87427_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = pc87427_device_add(&sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&pc87427_driver);
+exit:
+	return err;
+}
+
+static void __exit pc87427_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&pc87427_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("PC87427 hardware monitoring driver");
+MODULE_LICENSE("GPL");
+
+module_init(pc87427_init);
+module_exit(pc87427_exit);
diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c
new file mode 100644
index 0000000..5740888
--- /dev/null
+++ b/drivers/hwmon/pcf8591.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
+ * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
+ * the help of Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+
+/* Insmod parameters */
+
+static int input_mode;
+module_param(input_mode, int, 0);
+MODULE_PARM_DESC(input_mode,
+	"Analog input mode:\n"
+	" 0 = four single ended inputs\n"
+	" 1 = three differential inputs\n"
+	" 2 = single ended and differential mixed\n"
+	" 3 = two differential inputs\n");
+
+/*
+ * The PCF8591 control byte
+ *      7    6    5    4    3    2    1    0
+ *   |  0 |AOEF|   AIP   |  0 |AINC|  AICH   |
+ */
+
+/* Analog Output Enable Flag (analog output active if 1) */
+#define PCF8591_CONTROL_AOEF		0x40
+
+/*
+ * Analog Input Programming
+ * 0x00 = four single ended inputs
+ * 0x10 = three differential inputs
+ * 0x20 = single ended and differential mixed
+ * 0x30 = two differential inputs
+ */
+#define PCF8591_CONTROL_AIP_MASK	0x30
+
+/* Autoincrement Flag (switch on if 1) */
+#define PCF8591_CONTROL_AINC		0x04
+
+/*
+ * Channel selection
+ * 0x00 = channel 0
+ * 0x01 = channel 1
+ * 0x02 = channel 2
+ * 0x03 = channel 3
+ */
+#define PCF8591_CONTROL_AICH_MASK	0x03
+
+/* Initial values */
+#define PCF8591_INIT_CONTROL	((input_mode << 4) | PCF8591_CONTROL_AOEF)
+#define PCF8591_INIT_AOUT	0	/* DAC out = 0 */
+
+/* Conversions */
+#define REG_TO_SIGNED(reg)	(((reg) & 0x80) ? ((reg) - 256) : (reg))
+
+struct pcf8591_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+
+	u8 control;
+	u8 aout;
+};
+
+static void pcf8591_init_client(struct i2c_client *client);
+static int pcf8591_read_channel(struct device *dev, int channel);
+
+/* following are the sysfs callback functions */
+#define show_in_channel(channel)					\
+static ssize_t show_in##channel##_input(struct device *dev,		\
+					struct device_attribute *attr,	\
+					char *buf)			\
+{									\
+	return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
+}									\
+static DEVICE_ATTR(in##channel##_input, S_IRUGO,			\
+		   show_in##channel##_input, NULL);
+
+show_in_channel(0);
+show_in_channel(1);
+show_in_channel(2);
+show_in_channel(3);
+
+static ssize_t show_out0_ouput(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
+	return sprintf(buf, "%d\n", data->aout * 10);
+}
+
+static ssize_t set_out0_output(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	unsigned long val;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	val /= 10;
+	if (val > 255)
+		return -EINVAL;
+
+	data->aout = val;
+	i2c_smbus_write_byte_data(client, data->control, data->aout);
+	return count;
+}
+
+static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
+		   show_out0_ouput, set_out0_output);
+
+static ssize_t show_out0_enable(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
+	return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF)));
+}
+
+static ssize_t set_out0_enable(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->control |= PCF8591_CONTROL_AOEF;
+	else
+		data->control &= ~PCF8591_CONTROL_AOEF;
+	i2c_smbus_write_byte(client, data->control);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
+		   show_out0_enable, set_out0_enable);
+
+static struct attribute *pcf8591_attributes[] = {
+	&dev_attr_out0_enable.attr,
+	&dev_attr_out0_output.attr,
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	NULL
+};
+
+static const struct attribute_group pcf8591_attr_group = {
+	.attrs = pcf8591_attributes,
+};
+
+static struct attribute *pcf8591_attributes_opt[] = {
+	&dev_attr_in2_input.attr,
+	&dev_attr_in3_input.attr,
+	NULL
+};
+
+static const struct attribute_group pcf8591_attr_group_opt = {
+	.attrs = pcf8591_attributes_opt,
+};
+
+/*
+ * Real code
+ */
+
+static int pcf8591_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct pcf8591_data *data;
+	int err;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the PCF8591 chip */
+	pcf8591_init_client(client);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
+	if (err)
+		return err;
+
+	/* Register input2 if not in "two differential inputs" mode */
+	if (input_mode != 3) {
+		err = device_create_file(&client->dev, &dev_attr_in2_input);
+		if (err)
+			goto exit_sysfs_remove;
+	}
+
+	/* Register input3 only in "four single ended inputs" mode */
+	if (input_mode == 0) {
+		err = device_create_file(&client->dev, &dev_attr_in3_input);
+		if (err)
+			goto exit_sysfs_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_sysfs_remove;
+	}
+
+	return 0;
+
+exit_sysfs_remove:
+	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
+	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
+	return err;
+}
+
+static int pcf8591_remove(struct i2c_client *client)
+{
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
+	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
+	return 0;
+}
+
+/* Called when we have found a new PCF8591. */
+static void pcf8591_init_client(struct i2c_client *client)
+{
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+	data->control = PCF8591_INIT_CONTROL;
+	data->aout = PCF8591_INIT_AOUT;
+
+	i2c_smbus_write_byte_data(client, data->control, data->aout);
+
+	/*
+	 * The first byte transmitted contains the conversion code of the
+	 * previous read cycle. FLUSH IT!
+	 */
+	i2c_smbus_read_byte(client);
+}
+
+static int pcf8591_read_channel(struct device *dev, int channel)
+{
+	u8 value;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->update_lock);
+
+	if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) {
+		data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
+			      | channel;
+		i2c_smbus_write_byte(client, data->control);
+
+		/*
+		 * The first byte transmitted contains the conversion code of
+		 * the previous read cycle. FLUSH IT!
+		 */
+		i2c_smbus_read_byte(client);
+	}
+	value = i2c_smbus_read_byte(client);
+
+	mutex_unlock(&data->update_lock);
+
+	if ((channel == 2 && input_mode == 2) ||
+	    (channel != 3 && (input_mode == 1 || input_mode == 3)))
+		return 10 * REG_TO_SIGNED(value);
+	else
+		return 10 * value;
+}
+
+static const struct i2c_device_id pcf8591_id[] = {
+	{ "pcf8591", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8591_id);
+
+static struct i2c_driver pcf8591_driver = {
+	.driver = {
+		.name	= "pcf8591",
+	},
+	.probe		= pcf8591_probe,
+	.remove		= pcf8591_remove,
+	.id_table	= pcf8591_id,
+};
+
+static int __init pcf8591_init(void)
+{
+	if (input_mode < 0 || input_mode > 3) {
+		pr_warn("invalid input_mode (%d)\n", input_mode);
+		input_mode = 0;
+	}
+	return i2c_add_driver(&pcf8591_driver);
+}
+
+static void __exit pcf8591_exit(void)
+{
+	i2c_del_driver(&pcf8591_driver);
+}
+
+MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
+MODULE_DESCRIPTION("PCF8591 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pcf8591_init);
+module_exit(pcf8591_exit);
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
new file mode 100644
index 0000000..df6ebb2
--- /dev/null
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -0,0 +1,152 @@
+#
+# PMBus chip drivers configuration
+#
+
+menuconfig PMBUS
+	tristate "PMBus support"
+	depends on I2C
+	default n
+	help
+	  Say yes here if you want to enable PMBus support.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called pmbus_core.
+
+if PMBUS
+
+config SENSORS_PMBUS
+	tristate "Generic PMBus devices"
+	default y
+	help
+	  If you say yes here you get hardware monitoring support for generic
+	  PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
+	  MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, TPS544B20,
+	  TPS544B25, TPS544C20, TPS544C25, and UDT020.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called pmbus.
+
+config SENSORS_ADM1275
+	tristate "Analog Devices ADM1275 and compatibles"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Analog
+	  Devices ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap
+	  Controller and Digital Power Monitors.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called adm1275.
+
+config SENSORS_LM25066
+	tristate "National Semiconductor LM25066 and compatibles"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for National
+	  Semiconductor LM25056, LM25066, LM5064, and LM5066.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called lm25066.
+
+config SENSORS_LTC2978
+	tristate "Linear Technologies LTC2978 and compatibles"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Linear
+	  Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
+	  LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc2978.
+
+config SENSORS_LTC2978_REGULATOR
+	bool "Regulator support for LTC2978 and compatibles"
+	depends on SENSORS_LTC2978 && REGULATOR
+	help
+	  If you say yes here you get regulator support for Linear
+	  Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
+
+config SENSORS_MAX16064
+	tristate "Maxim MAX16064"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Maxim
+	  MAX16064.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called max16064.
+
+config SENSORS_MAX20751
+	tristate "Maxim MAX20751"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Maxim
+	  MAX20751.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called max20751.
+
+config SENSORS_MAX34440
+	tristate "Maxim MAX34440 and compatibles"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Maxim
+	  MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called max34440.
+
+config SENSORS_MAX8688
+	tristate "Maxim MAX8688"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Maxim
+	  MAX8688.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called max8688.
+
+config SENSORS_TPS40422
+	tristate "TI TPS40422"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for TI
+	  TPS40422.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called tps40422.
+
+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.
+
+config SENSORS_ZL6100
+	tristate "Intersil ZL6100 and compatibles"
+	default n
+	help
+	  If you say yes here you get hardware monitoring support for Intersil
+	  ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105,
+	  ZL9101M, and ZL9117M Digital DC/DC Controllers, as well as for
+	  Ericsson BMR450, BMR451, BMR462, BMR463, and BMR464.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called zl6100.
+
+endif # PMBUS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
new file mode 100644
index 0000000..bce046d
--- /dev/null
+++ b/drivers/hwmon/pmbus/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for PMBus chip drivers.
+#
+
+obj-$(CONFIG_PMBUS)		+= pmbus_core.o
+obj-$(CONFIG_SENSORS_PMBUS)	+= pmbus.o
+obj-$(CONFIG_SENSORS_ADM1275)	+= adm1275.o
+obj-$(CONFIG_SENSORS_LM25066)	+= lm25066.o
+obj-$(CONFIG_SENSORS_LTC2978)	+= ltc2978.o
+obj-$(CONFIG_SENSORS_MAX16064)	+= max16064.o
+obj-$(CONFIG_SENSORS_MAX20751)	+= max20751.o
+obj-$(CONFIG_SENSORS_MAX34440)	+= max34440.o
+obj-$(CONFIG_SENSORS_MAX8688)	+= max8688.o
+obj-$(CONFIG_SENSORS_TPS40422)	+= tps40422.o
+obj-$(CONFIG_SENSORS_UCD9000)	+= ucd9000.o
+obj-$(CONFIG_SENSORS_UCD9200)	+= ucd9200.o
+obj-$(CONFIG_SENSORS_ZL6100)	+= zl6100.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
new file mode 100644
index 0000000..188af4c
--- /dev/null
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -0,0 +1,557 @@
+/*
+ * 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 <linux/bitops.h>
+#include "pmbus.h"
+
+enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };
+
+#define ADM1275_MFR_STATUS_IOUT_WARN2	BIT(0)
+#define ADM1293_MFR_STATUS_VAUX_UV_WARN	BIT(5)
+#define ADM1293_MFR_STATUS_VAUX_OV_WARN	BIT(6)
+
+#define ADM1275_PEAK_IOUT		0xd0
+#define ADM1275_PEAK_VIN		0xd1
+#define ADM1275_PEAK_VOUT		0xd2
+#define ADM1275_PMON_CONFIG		0xd4
+
+#define ADM1275_VIN_VOUT_SELECT		BIT(6)
+#define ADM1275_VRANGE			BIT(5)
+#define ADM1075_IRANGE_50		BIT(4)
+#define ADM1075_IRANGE_25		BIT(3)
+#define ADM1075_IRANGE_MASK		(BIT(3) | BIT(4))
+
+#define ADM1293_IRANGE_25		0
+#define ADM1293_IRANGE_50		BIT(6)
+#define ADM1293_IRANGE_100		BIT(7)
+#define ADM1293_IRANGE_200		(BIT(6) | BIT(7))
+#define ADM1293_IRANGE_MASK		(BIT(6) | BIT(7))
+
+#define ADM1293_VIN_SEL_012		BIT(2)
+#define ADM1293_VIN_SEL_074		BIT(3)
+#define ADM1293_VIN_SEL_210		(BIT(2) | BIT(3))
+#define ADM1293_VIN_SEL_MASK		(BIT(2) | BIT(3))
+
+#define ADM1293_VAUX_EN			BIT(1)
+
+#define ADM1275_IOUT_WARN2_LIMIT	0xd7
+#define ADM1275_DEVICE_CONFIG		0xd8
+
+#define ADM1275_IOUT_WARN2_SELECT	BIT(4)
+
+#define ADM1276_PEAK_PIN		0xda
+#define ADM1075_READ_VAUX		0xdd
+#define ADM1075_VAUX_OV_WARN_LIMIT	0xde
+#define ADM1075_VAUX_UV_WARN_LIMIT	0xdf
+#define ADM1293_IOUT_MIN		0xe3
+#define ADM1293_PIN_MIN			0xe4
+#define ADM1075_VAUX_STATUS		0xf6
+
+#define ADM1075_VAUX_OV_WARN		BIT(7)
+#define ADM1075_VAUX_UV_WARN		BIT(6)
+
+struct adm1275_data {
+	int id;
+	bool have_oc_fault;
+	bool have_uc_fault;
+	bool have_vout;
+	bool have_vaux_status;
+	bool have_mfr_vaux_status;
+	bool have_iout_min;
+	bool have_pin_min;
+	bool have_pin_max;
+	struct pmbus_driver_info info;
+};
+
+#define to_adm1275_data(x)  container_of(x, struct adm1275_data, info)
+
+struct coefficients {
+	s16 m;
+	s16 b;
+	s16 R;
+};
+
+static const struct coefficients adm1075_coefficients[] = {
+	[0] = { 27169, 0, -1 },		/* voltage */
+	[1] = { 806, 20475, -1 },	/* current, irange25 */
+	[2] = { 404, 20475, -1 },	/* current, irange50 */
+	[3] = { 0, -1, 8549 },		/* power, irange25 */
+	[4] = { 0, -1, 4279 },		/* power, irange50 */
+};
+
+static const struct coefficients adm1275_coefficients[] = {
+	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
+	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
+	[2] = { 807, 20475, -1 },	/* current */
+};
+
+static const struct coefficients adm1276_coefficients[] = {
+	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
+	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
+	[2] = { 807, 20475, -1 },	/* current */
+	[3] = { 6043, 0, -2 },		/* power, vrange set */
+	[4] = { 2115, 0, -1 },		/* power, vrange not set */
+};
+
+static const struct coefficients adm1293_coefficients[] = {
+	[0] = { 3333, -1, 0 },		/* voltage, vrange 1.2V */
+	[1] = { 5552, -5, -1 },		/* voltage, vrange 7.4V */
+	[2] = { 19604, -50, -2 },	/* voltage, vrange 21V */
+	[3] = { 8000, -100, -2 },	/* current, irange25 */
+	[4] = { 4000, -100, -2 },	/* current, irange50 */
+	[5] = { 20000, -1000, -3 },	/* current, irange100 */
+	[6] = { 10000, -1000, -3 },	/* current, irange200 */
+	[7] = { 10417, 0, -1 },		/* power, 1.2V, irange25 */
+	[8] = { 5208, 0, -1 },		/* power, 1.2V, irange50 */
+	[9] = { 26042, 0, -2 },		/* power, 1.2V, irange100 */
+	[10] = { 13021, 0, -2 },	/* power, 1.2V, irange200 */
+	[11] = { 17351, 0, -2 },	/* power, 7.4V, irange25 */
+	[12] = { 8676, 0, -2 },		/* power, 7.4V, irange50 */
+	[13] = { 4338, 0, -2 },		/* power, 7.4V, irange100 */
+	[14] = { 21689, 0, -3 },	/* power, 7.4V, irange200 */
+	[15] = { 6126, 0, -2 },		/* power, 21V, irange25 */
+	[16] = { 30631, 0, -3 },	/* power, 21V, irange50 */
+	[17] = { 15316, 0, -3 },	/* power, 21V, irange100 */
+	[18] = { 7658, 0, -3 },		/* power, 21V, irange200 */
+};
+
+static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct adm1275_data *data = to_adm1275_data(info);
+	int ret = 0;
+
+	if (page)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_IOUT_UC_FAULT_LIMIT:
+		if (!data->have_uc_fault)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+		break;
+	case PMBUS_IOUT_OC_FAULT_LIMIT:
+		if (!data->have_oc_fault)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+		break;
+	case PMBUS_VOUT_OV_WARN_LIMIT:
+		if (data->have_vout)
+			return -ENODATA;
+		ret = pmbus_read_word_data(client, 0,
+					   ADM1075_VAUX_OV_WARN_LIMIT);
+		break;
+	case PMBUS_VOUT_UV_WARN_LIMIT:
+		if (data->have_vout)
+			return -ENODATA;
+		ret = pmbus_read_word_data(client, 0,
+					   ADM1075_VAUX_UV_WARN_LIMIT);
+		break;
+	case PMBUS_READ_VOUT:
+		if (data->have_vout)
+			return -ENODATA;
+		ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MIN:
+		if (!data->have_iout_min)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
+		break;
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
+		break;
+	case PMBUS_VIRT_READ_VIN_MAX:
+		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
+		break;
+	case PMBUS_VIRT_READ_PIN_MIN:
+		if (!data->have_pin_min)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN);
+		break;
+	case PMBUS_VIRT_READ_PIN_MAX:
+		if (!data->have_pin_max)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+	case PMBUS_VIRT_RESET_VIN_HISTORY:
+		break;
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		if (!data->have_pin_max)
+			return -ENXIO;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
+				   u16 word)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct adm1275_data *data = to_adm1275_data(info);
+	int ret;
+
+	if (page)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_IOUT_UC_FAULT_LIMIT:
+	case PMBUS_IOUT_OC_FAULT_LIMIT:
+		ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
+					    word);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
+		if (!ret && data->have_iout_min)
+			ret = pmbus_write_word_data(client, 0,
+						    ADM1293_IOUT_MIN, 0);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
+		break;
+	case PMBUS_VIRT_RESET_VIN_HISTORY:
+		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
+		break;
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
+		if (!ret && data->have_pin_min)
+			ret = pmbus_write_word_data(client, 0,
+						    ADM1293_PIN_MIN, 0);
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct adm1275_data *data = to_adm1275_data(info);
+	int mfr_status, ret;
+
+	if (page > 0)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_STATUS_IOUT:
+		ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
+		if (ret < 0)
+			break;
+		if (!data->have_oc_fault && !data->have_uc_fault)
+			break;
+		mfr_status = pmbus_read_byte_data(client, page,
+						  PMBUS_STATUS_MFR_SPECIFIC);
+		if (mfr_status < 0)
+			return mfr_status;
+		if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
+			ret |= data->have_oc_fault ?
+			  PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
+		}
+		break;
+	case PMBUS_STATUS_VOUT:
+		if (data->have_vout)
+			return -ENODATA;
+		ret = 0;
+		if (data->have_vaux_status) {
+			mfr_status = pmbus_read_byte_data(client, 0,
+							  ADM1075_VAUX_STATUS);
+			if (mfr_status < 0)
+				return mfr_status;
+			if (mfr_status & ADM1075_VAUX_OV_WARN)
+				ret |= PB_VOLTAGE_OV_WARNING;
+			if (mfr_status & ADM1075_VAUX_UV_WARN)
+				ret |= PB_VOLTAGE_UV_WARNING;
+		} else if (data->have_mfr_vaux_status) {
+			mfr_status = pmbus_read_byte_data(client, page,
+						PMBUS_STATUS_MFR_SPECIFIC);
+			if (mfr_status < 0)
+				return mfr_status;
+			if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN)
+				ret |= PB_VOLTAGE_OV_WARNING;
+			if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN)
+				ret |= PB_VOLTAGE_UV_WARNING;
+		}
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static const struct i2c_device_id adm1275_id[] = {
+	{ "adm1075", adm1075 },
+	{ "adm1275", adm1275 },
+	{ "adm1276", adm1276 },
+	{ "adm1293", adm1293 },
+	{ "adm1294", adm1294 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adm1275_id);
+
+static int adm1275_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+	int config, device_config;
+	int ret;
+	struct pmbus_driver_info *info;
+	struct adm1275_data *data;
+	const struct i2c_device_id *mid;
+	const struct coefficients *coefficients;
+	int vindex = -1, voindex = -1, cindex = -1, pindex = -1;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_BYTE_DATA
+				     | I2C_FUNC_SMBUS_BLOCK_DATA))
+		return -ENODEV;
+
+	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
+		return ret;
+	}
+	if (ret != 3 || strncmp(block_buffer, "ADI", 3)) {
+		dev_err(&client->dev, "Unsupported Manufacturer ID\n");
+		return -ENODEV;
+	}
+
+	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+		return ret;
+	}
+	for (mid = adm1275_id; mid->name[0]; mid++) {
+		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+			break;
+	}
+	if (!mid->name[0]) {
+		dev_err(&client->dev, "Unsupported device\n");
+		return -ENODEV;
+	}
+
+	if (id->driver_data != mid->driver_data)
+		dev_notice(&client->dev,
+			   "Device mismatch: Configured %s, detected %s\n",
+			   id->name, mid->name);
+
+	config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+	if (config < 0)
+		return config;
+
+	device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
+	if (device_config < 0)
+		return device_config;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->id = mid->driver_data;
+
+	info = &data->info;
+
+	info->pages = 1;
+	info->format[PSC_VOLTAGE_IN] = direct;
+	info->format[PSC_VOLTAGE_OUT] = direct;
+	info->format[PSC_CURRENT_OUT] = direct;
+	info->format[PSC_POWER] = direct;
+	info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+
+	info->read_word_data = adm1275_read_word_data;
+	info->read_byte_data = adm1275_read_byte_data;
+	info->write_word_data = adm1275_write_word_data;
+
+	switch (data->id) {
+	case adm1075:
+		if (device_config & ADM1275_IOUT_WARN2_SELECT)
+			data->have_oc_fault = true;
+		else
+			data->have_uc_fault = true;
+		data->have_pin_max = true;
+		data->have_vaux_status = true;
+
+		coefficients = adm1075_coefficients;
+		vindex = 0;
+		switch (config & ADM1075_IRANGE_MASK) {
+		case ADM1075_IRANGE_25:
+			cindex = 1;
+			pindex = 3;
+			break;
+		case ADM1075_IRANGE_50:
+			cindex = 2;
+			pindex = 4;
+			break;
+		default:
+			dev_err(&client->dev, "Invalid input current range");
+			break;
+		}
+
+		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
+		  | PMBUS_HAVE_STATUS_INPUT;
+		if (config & ADM1275_VIN_VOUT_SELECT)
+			info->func[0] |=
+			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+		break;
+	case adm1275:
+		if (device_config & ADM1275_IOUT_WARN2_SELECT)
+			data->have_oc_fault = true;
+		else
+			data->have_uc_fault = true;
+		data->have_vout = true;
+
+		coefficients = adm1275_coefficients;
+		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
+		cindex = 2;
+
+		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;
+		break;
+	case adm1276:
+		if (device_config & ADM1275_IOUT_WARN2_SELECT)
+			data->have_oc_fault = true;
+		else
+			data->have_uc_fault = true;
+		data->have_vout = true;
+		data->have_pin_max = true;
+
+		coefficients = adm1276_coefficients;
+		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
+		cindex = 2;
+		pindex = (config & ADM1275_VRANGE) ? 3 : 4;
+
+		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
+		  | PMBUS_HAVE_STATUS_INPUT;
+		if (config & ADM1275_VIN_VOUT_SELECT)
+			info->func[0] |=
+			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+		break;
+	case adm1293:
+	case adm1294:
+		data->have_iout_min = true;
+		data->have_pin_min = true;
+		data->have_pin_max = true;
+		data->have_mfr_vaux_status = true;
+
+		coefficients = adm1293_coefficients;
+
+		voindex = 0;
+		switch (config & ADM1293_VIN_SEL_MASK) {
+		case ADM1293_VIN_SEL_012:	/* 1.2V */
+			vindex = 0;
+			break;
+		case ADM1293_VIN_SEL_074:	/* 7.4V */
+			vindex = 1;
+			break;
+		case ADM1293_VIN_SEL_210:	/* 21V */
+			vindex = 2;
+			break;
+		default:			/* disabled */
+			break;
+		}
+
+		switch (config & ADM1293_IRANGE_MASK) {
+		case ADM1293_IRANGE_25:
+			cindex = 3;
+			break;
+		case ADM1293_IRANGE_50:
+			cindex = 4;
+			break;
+		case ADM1293_IRANGE_100:
+			cindex = 5;
+			break;
+		case ADM1293_IRANGE_200:
+			cindex = 6;
+			break;
+		}
+
+		if (vindex >= 0)
+			pindex = 7 + vindex * 4 + (cindex - 3);
+
+		if (config & ADM1293_VAUX_EN)
+			info->func[0] |=
+				PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+
+		info->func[0] |= PMBUS_HAVE_PIN |
+			PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+
+		break;
+	default:
+		dev_err(&client->dev, "Unsupported device\n");
+		return -ENODEV;
+	}
+
+	if (voindex < 0)
+		voindex = vindex;
+	if (vindex >= 0) {
+		info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m;
+		info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b;
+		info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R;
+	}
+	if (voindex >= 0) {
+		info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m;
+		info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b;
+		info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
+	}
+	if (cindex >= 0) {
+		info->m[PSC_CURRENT_OUT] = coefficients[cindex].m;
+		info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
+		info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
+	}
+	if (pindex >= 0) {
+		info->m[PSC_POWER] = coefficients[pindex].m;
+		info->b[PSC_POWER] = coefficients[pindex].b;
+		info->R[PSC_POWER] = coefficients[pindex].R;
+	}
+
+	return pmbus_do_probe(client, id, info);
+}
+
+static struct i2c_driver adm1275_driver = {
+	.driver = {
+		   .name = "adm1275",
+		   },
+	.probe = adm1275_probe,
+	.remove = pmbus_do_remove,
+	.id_table = adm1275_id,
+};
+
+module_i2c_driver(adm1275_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
new file mode 100644
index 0000000..a3d912c
--- /dev/null
+++ b/drivers/hwmon/pmbus/lm25066.c
@@ -0,0 +1,531 @@
+/*
+ * Hardware monitoring driver for LM25056 / LM25063 / LM25066 / LM5064 / LM5066
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/bitops.h>
+#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"
+
+enum chips { lm25056, lm25063, lm25066, lm5064, lm5066 };
+
+#define LM25066_READ_VAUX		0xd0
+#define LM25066_MFR_READ_IIN		0xd1
+#define LM25066_MFR_READ_PIN		0xd2
+#define LM25066_MFR_IIN_OC_WARN_LIMIT	0xd3
+#define LM25066_MFR_PIN_OP_WARN_LIMIT	0xd4
+#define LM25066_READ_PIN_PEAK		0xd5
+#define LM25066_CLEAR_PIN_PEAK		0xd6
+#define LM25066_DEVICE_SETUP		0xd9
+#define LM25066_READ_AVG_VIN		0xdc
+#define LM25066_READ_AVG_VOUT		0xdd
+#define LM25066_READ_AVG_IIN		0xde
+#define LM25066_READ_AVG_PIN		0xdf
+
+#define LM25066_DEV_SETUP_CL		BIT(4)	/* Current limit */
+
+/* LM25056 only */
+
+#define LM25056_VAUX_OV_WARN_LIMIT	0xe3
+#define LM25056_VAUX_UV_WARN_LIMIT	0xe4
+
+#define LM25056_MFR_STS_VAUX_OV_WARN	BIT(1)
+#define LM25056_MFR_STS_VAUX_UV_WARN	BIT(0)
+
+/* LM25063 only */
+
+#define LM25063_READ_VOUT_MAX		0xe5
+#define LM25063_READ_VOUT_MIN		0xe6
+
+struct __coeff {
+	short m, b, R;
+};
+
+#define PSC_CURRENT_IN_L	(PSC_NUM_CLASSES)
+#define PSC_POWER_L		(PSC_NUM_CLASSES + 1)
+
+static struct __coeff lm25066_coeff[5][PSC_NUM_CLASSES + 2] = {
+	[lm25056] = {
+		[PSC_VOLTAGE_IN] = {
+			.m = 16296,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN] = {
+			.m = 13797,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN_L] = {
+			.m = 6726,
+			.R = -2,
+		},
+		[PSC_POWER] = {
+			.m = 5501,
+			.R = -3,
+		},
+		[PSC_POWER_L] = {
+			.m = 26882,
+			.R = -4,
+		},
+		[PSC_TEMPERATURE] = {
+			.m = 1580,
+			.b = -14500,
+			.R = -2,
+		},
+	},
+	[lm25066] = {
+		[PSC_VOLTAGE_IN] = {
+			.m = 22070,
+			.R = -2,
+		},
+		[PSC_VOLTAGE_OUT] = {
+			.m = 22070,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN] = {
+			.m = 13661,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN_L] = {
+			.m = 6852,
+			.R = -2,
+		},
+		[PSC_POWER] = {
+			.m = 736,
+			.R = -2,
+		},
+		[PSC_POWER_L] = {
+			.m = 369,
+			.R = -2,
+		},
+		[PSC_TEMPERATURE] = {
+			.m = 16,
+		},
+	},
+	[lm25063] = {
+		[PSC_VOLTAGE_IN] = {
+			.m = 16000,
+			.R = -2,
+		},
+		[PSC_VOLTAGE_OUT] = {
+			.m = 16000,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN] = {
+			.m = 10000,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN_L] = {
+			.m = 10000,
+			.R = -2,
+		},
+		[PSC_POWER] = {
+			.m = 5000,
+			.R = -3,
+		},
+		[PSC_POWER_L] = {
+			.m = 5000,
+			.R = -3,
+		},
+		[PSC_TEMPERATURE] = {
+			.m = 15596,
+			.R = -3,
+		},
+	},
+	[lm5064] = {
+		[PSC_VOLTAGE_IN] = {
+			.m = 4611,
+			.R = -2,
+		},
+		[PSC_VOLTAGE_OUT] = {
+			.m = 4621,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN] = {
+			.m = 10742,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN_L] = {
+			.m = 5456,
+			.R = -2,
+		},
+		[PSC_POWER] = {
+			.m = 1204,
+			.R = -3,
+		},
+		[PSC_POWER_L] = {
+			.m = 612,
+			.R = -3,
+		},
+		[PSC_TEMPERATURE] = {
+			.m = 16,
+		},
+	},
+	[lm5066] = {
+		[PSC_VOLTAGE_IN] = {
+			.m = 4587,
+			.R = -2,
+		},
+		[PSC_VOLTAGE_OUT] = {
+			.m = 4587,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN] = {
+			.m = 10753,
+			.R = -2,
+		},
+		[PSC_CURRENT_IN_L] = {
+			.m = 5405,
+			.R = -2,
+		},
+		[PSC_POWER] = {
+			.m = 1204,
+			.R = -3,
+		},
+		[PSC_POWER_L] = {
+			.m = 605,
+			.R = -3,
+		},
+		[PSC_TEMPERATURE] = {
+			.m = 16,
+		},
+	},
+};
+
+struct lm25066_data {
+	int id;
+	u16 rlimit;			/* Maximum register value */
+	struct pmbus_driver_info info;
+};
+
+#define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
+
+static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct lm25066_data *data = to_lm25066_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VMON:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
+		if (ret < 0)
+			break;
+		/* Adjust returned value to match VIN coefficients */
+		switch (data->id) {
+		case lm25056:
+			/* VIN: 6.14 mV VAUX: 293 uV LSB */
+			ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+			break;
+		case lm25063:
+			/* VIN: 6.25 mV VAUX: 200.0 uV LSB */
+			ret = DIV_ROUND_CLOSEST(ret * 20, 625);
+			break;
+		case lm25066:
+			/* VIN: 4.54 mV VAUX: 283.2 uV LSB */
+			ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
+			break;
+		case lm5064:
+			/* VIN: 4.53 mV VAUX: 700 uV LSB */
+			ret = DIV_ROUND_CLOSEST(ret * 70, 453);
+			break;
+		case lm5066:
+			/* VIN: 2.18 mV VAUX: 725 uV LSB */
+			ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
+			break;
+		}
+		break;
+	case PMBUS_READ_IIN:
+		ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
+		break;
+	case PMBUS_READ_PIN:
+		ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
+		break;
+	case PMBUS_IIN_OC_WARN_LIMIT:
+		ret = pmbus_read_word_data(client, 0,
+					   LM25066_MFR_IIN_OC_WARN_LIMIT);
+		break;
+	case PMBUS_PIN_OP_WARN_LIMIT:
+		ret = pmbus_read_word_data(client, 0,
+					   LM25066_MFR_PIN_OP_WARN_LIMIT);
+		break;
+	case PMBUS_VIRT_READ_VIN_AVG:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
+		break;
+	case PMBUS_VIRT_READ_VOUT_AVG:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
+		break;
+	case PMBUS_VIRT_READ_IIN_AVG:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
+		break;
+	case PMBUS_VIRT_READ_PIN_AVG:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
+		break;
+	case PMBUS_VIRT_READ_PIN_MAX:
+		ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
+		break;
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int lm25063_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MAX);
+		break;
+	case PMBUS_VIRT_READ_VOUT_MIN:
+		ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MIN);
+		break;
+	default:
+		ret = lm25066_read_word_data(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		ret = pmbus_read_word_data(client, 0,
+					   LM25056_VAUX_UV_WARN_LIMIT);
+		if (ret < 0)
+			break;
+		/* Adjust returned value to match VIN coefficients */
+		ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+		break;
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		ret = pmbus_read_word_data(client, 0,
+					   LM25056_VAUX_OV_WARN_LIMIT);
+		if (ret < 0)
+			break;
+		/* Adjust returned value to match VIN coefficients */
+		ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+		break;
+	default:
+		ret = lm25066_read_word_data(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	int ret, s;
+
+	switch (reg) {
+	case PMBUS_VIRT_STATUS_VMON:
+		ret = pmbus_read_byte_data(client, 0,
+					   PMBUS_STATUS_MFR_SPECIFIC);
+		if (ret < 0)
+			break;
+		s = 0;
+		if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
+			s |= PB_VOLTAGE_UV_WARNING;
+		if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
+			s |= PB_VOLTAGE_OV_WARNING;
+		ret = s;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
+				   u16 word)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct lm25066_data *data = to_lm25066_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_POUT_OP_FAULT_LIMIT:
+	case PMBUS_POUT_OP_WARN_LIMIT:
+	case PMBUS_VOUT_UV_WARN_LIMIT:
+	case PMBUS_OT_FAULT_LIMIT:
+	case PMBUS_OT_WARN_LIMIT:
+	case PMBUS_IIN_OC_FAULT_LIMIT:
+	case PMBUS_VIN_UV_WARN_LIMIT:
+	case PMBUS_VIN_UV_FAULT_LIMIT:
+	case PMBUS_VIN_OV_FAULT_LIMIT:
+	case PMBUS_VIN_OV_WARN_LIMIT:
+		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
+		ret = pmbus_write_word_data(client, 0, reg, word);
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_IIN_OC_WARN_LIMIT:
+		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
+		ret = pmbus_write_word_data(client, 0,
+					    LM25066_MFR_IIN_OC_WARN_LIMIT,
+					    word);
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_PIN_OP_WARN_LIMIT:
+		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
+		ret = pmbus_write_word_data(client, 0,
+					    LM25066_MFR_PIN_OP_WARN_LIMIT,
+					    word);
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		/* Adjust from VIN coefficients (for LM25056) */
+		word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
+		ret = pmbus_write_word_data(client, 0,
+					    LM25056_VAUX_UV_WARN_LIMIT, word);
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		/* Adjust from VIN coefficients (for LM25056) */
+		word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
+		ret = pmbus_write_word_data(client, 0,
+					    LM25056_VAUX_OV_WARN_LIMIT, word);
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int lm25066_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int config;
+	struct lm25066_data *data;
+	struct pmbus_driver_info *info;
+	struct __coeff *coeff;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
+	if (config < 0)
+		return config;
+
+	data->id = id->driver_data;
+	info = &data->info;
+
+	info->pages = 1;
+	info->format[PSC_VOLTAGE_IN] = direct;
+	info->format[PSC_VOLTAGE_OUT] = direct;
+	info->format[PSC_CURRENT_IN] = direct;
+	info->format[PSC_TEMPERATURE] = direct;
+	info->format[PSC_POWER] = direct;
+
+	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
+	  | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
+	  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+
+	if (data->id == lm25056) {
+		info->func[0] |= PMBUS_HAVE_STATUS_VMON;
+		info->read_word_data = lm25056_read_word_data;
+		info->read_byte_data = lm25056_read_byte_data;
+		data->rlimit = 0x0fff;
+	} else if (data->id == lm25063) {
+		info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_POUT;
+		info->read_word_data = lm25063_read_word_data;
+		data->rlimit = 0xffff;
+	} else {
+		info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+		info->read_word_data = lm25066_read_word_data;
+		data->rlimit = 0x0fff;
+	}
+	info->write_word_data = lm25066_write_word_data;
+
+	coeff = &lm25066_coeff[data->id][0];
+	info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
+	info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
+	info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
+	info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
+	info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
+	info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
+	info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
+	info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
+	info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
+	info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
+	info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
+	info->b[PSC_POWER] = coeff[PSC_POWER].b;
+	info->R[PSC_POWER] = coeff[PSC_POWER].R;
+	if (config & LM25066_DEV_SETUP_CL) {
+		info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
+		info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
+	} else {
+		info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
+		info->m[PSC_POWER] = coeff[PSC_POWER].m;
+	}
+
+	return pmbus_do_probe(client, id, info);
+}
+
+static const struct i2c_device_id lm25066_id[] = {
+	{"lm25056", lm25056},
+	{"lm25063", lm25063},
+	{"lm25066", lm25066},
+	{"lm5064", lm5064},
+	{"lm5066", lm5066},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, lm25066_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver lm25066_driver = {
+	.driver = {
+		   .name = "lm25066",
+		   },
+	.probe = lm25066_probe,
+	.remove = pmbus_do_remove,
+	.id_table = lm25066_id,
+};
+
+module_i2c_driver(lm25066_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
new file mode 100644
index 0000000..58b789c
--- /dev/null
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -0,0 +1,792 @@
+/*
+ * Hardware monitoring driver for LTC2978 and compatible chips.
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013, 2014, 2015 Guenter Roeck
+ * Copyright (c) 2015 Linear Technology
+ *
+ * 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/delay.h>
+#include <linux/jiffies.h>
+#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/regulator/driver.h>
+#include "pmbus.h"
+
+enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
+	ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 };
+
+/* Common for all chips */
+#define LTC2978_MFR_VOUT_PEAK		0xdd
+#define LTC2978_MFR_VIN_PEAK		0xde
+#define LTC2978_MFR_TEMPERATURE_PEAK	0xdf
+#define LTC2978_MFR_SPECIAL_ID		0xe7	/* Undocumented on LTC3882 */
+#define LTC2978_MFR_COMMON		0xef
+
+/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */
+#define LTC2978_MFR_VOUT_MIN		0xfb
+#define LTC2978_MFR_VIN_MIN		0xfc
+#define LTC2978_MFR_TEMPERATURE_MIN	0xfd
+
+/* LTC2974, LTC2975 */
+#define LTC2974_MFR_IOUT_PEAK		0xd7
+#define LTC2974_MFR_IOUT_MIN		0xd8
+
+/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */
+#define LTC3880_MFR_IOUT_PEAK		0xd7
+#define LTC3880_MFR_CLEAR_PEAKS		0xe3
+#define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4
+
+/* LTC3883 and LTC3886 only */
+#define LTC3883_MFR_IIN_PEAK		0xe1
+
+/* LTC2975 only */
+#define LTC2975_MFR_IIN_PEAK		0xc4
+#define LTC2975_MFR_IIN_MIN		0xc5
+#define LTC2975_MFR_PIN_PEAK		0xc6
+#define LTC2975_MFR_PIN_MIN		0xc7
+
+#define LTC2978_ID_MASK			0xfff0
+
+#define LTC2974_ID			0x0210
+#define LTC2975_ID			0x0220
+#define LTC2977_ID			0x0130
+#define LTC2978_ID_REV1			0x0110	/* Early revision */
+#define LTC2978_ID_REV2			0x0120
+#define LTC2980_ID_A			0x8030	/* A/B for two die IDs */
+#define LTC2980_ID_B			0x8040
+#define LTC3880_ID			0x4020
+#define LTC3882_ID			0x4200
+#define LTC3882_ID_D1			0x4240	/* Dash 1 */
+#define LTC3883_ID			0x4300
+#define LTC3886_ID			0x4600
+#define LTC3887_ID			0x4700
+#define LTM2987_ID_A			0x8010	/* A/B for two die IDs */
+#define LTM2987_ID_B			0x8020
+#define LTM4675_ID			0x47a0
+#define LTM4676_ID_REV1			0x4400
+#define LTM4676_ID_REV2			0x4480
+#define LTM4676A_ID			0x47e0
+
+#define LTC2974_NUM_PAGES		4
+#define LTC2978_NUM_PAGES		8
+#define LTC3880_NUM_PAGES		2
+#define LTC3883_NUM_PAGES		1
+
+#define LTC_POLL_TIMEOUT		100	/* in milli-seconds */
+
+#define LTC_NOT_BUSY			BIT(5)
+#define LTC_NOT_PENDING			BIT(4)
+
+/*
+ * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
+ * happens pretty much each time chip data is updated. Raw peak data therefore
+ * does not provide much value. To be able to provide useful peak data, keep an
+ * internal cache of measured peak data, which is only cleared if an explicit
+ * "clear peak" command is executed for the sensor in question.
+ */
+
+struct ltc2978_data {
+	enum chips id;
+	u16 vin_min, vin_max;
+	u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
+	u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
+	u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
+	u16 iin_min, iin_max;
+	u16 pin_min, pin_max;
+	u16 temp2_max;
+	struct pmbus_driver_info info;
+	u32 features;
+};
+#define to_ltc2978_data(x)  container_of(x, struct ltc2978_data, info)
+
+#define FEAT_CLEAR_PEAKS	BIT(0)
+#define FEAT_NEEDS_POLLING	BIT(1)
+
+#define has_clear_peaks(d)	((d)->features & FEAT_CLEAR_PEAKS)
+#define needs_polling(d)	((d)->features & FEAT_NEEDS_POLLING)
+
+static int ltc_wait_ready(struct i2c_client *client)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(LTC_POLL_TIMEOUT);
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int status;
+	u8 mask;
+
+	if (!needs_polling(data))
+		return 0;
+
+	/*
+	 * LTC3883 does not support LTC_NOT_PENDING, even though
+	 * the datasheet claims that it does.
+	 */
+	mask = LTC_NOT_BUSY;
+	if (data->id != ltc3883)
+		mask |= LTC_NOT_PENDING;
+
+	do {
+		status = pmbus_read_byte_data(client, 0, LTC2978_MFR_COMMON);
+		if (status == -EBADMSG || status == -ENXIO) {
+			/* PEC error or NACK: chip may be busy, try again */
+			usleep_range(50, 100);
+			continue;
+		}
+		if (status < 0)
+			return status;
+
+		if ((status & mask) == mask)
+			return 0;
+
+		usleep_range(50, 100);
+	} while (time_before(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	ret = ltc_wait_ready(client);
+	if (ret < 0)
+		return ret;
+
+	return pmbus_read_word_data(client, page, reg);
+}
+
+static int ltc_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	ret = ltc_wait_ready(client);
+	if (ret < 0)
+		return ret;
+
+	return pmbus_read_byte_data(client, page, reg);
+}
+
+static int ltc_write_byte(struct i2c_client *client, int page, u8 byte)
+{
+	int ret;
+
+	ret = ltc_wait_ready(client);
+	if (ret < 0)
+		return ret;
+
+	return pmbus_write_byte(client, page, byte);
+}
+
+static inline int lin11_to_val(int data)
+{
+	s16 e = ((s16)data) >> 11;
+	s32 m = (((s16)(data << 5)) >> 5);
+
+	/*
+	 * mantissa is 10 bit + sign, exponent adds up to 15 bit.
+	 * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
+	 */
+	e += 6;
+	return (e < 0 ? m >> -e : m << e);
+}
+
+static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client,
+		       int page, int reg, u16 *pmax)
+{
+	int ret;
+
+	ret = ltc_read_word_data(client, page, reg);
+	if (ret >= 0) {
+		if (lin11_to_val(ret) > lin11_to_val(*pmax))
+			*pmax = ret;
+		ret = *pmax;
+	}
+	return ret;
+}
+
+static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client,
+		       int page, int reg, u16 *pmin)
+{
+	int ret;
+
+	ret = ltc_read_word_data(client, page, reg);
+	if (ret >= 0) {
+		if (lin11_to_val(ret) < lin11_to_val(*pmin))
+			*pmin = ret;
+		ret = *pmin;
+	}
+	return ret;
+}
+
+static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
+					 int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VIN_MAX:
+		ret = ltc_get_max(data, client, page, LTC2978_MFR_VIN_PEAK,
+				  &data->vin_max);
+		break;
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
+		if (ret >= 0) {
+			/*
+			 * VOUT is 16 bit unsigned with fixed exponent,
+			 * so we can compare it directly
+			 */
+			if (ret > data->vout_max[page])
+				data->vout_max[page] = ret;
+			ret = data->vout_max[page];
+		}
+		break;
+	case PMBUS_VIRT_READ_TEMP_MAX:
+		ret = ltc_get_max(data, client, page,
+				  LTC2978_MFR_TEMPERATURE_PEAK,
+				  &data->temp_max[page]);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+	case PMBUS_VIRT_RESET_VIN_HISTORY:
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = ltc_wait_ready(client);
+		if (ret < 0)
+			return ret;
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VIN_MIN:
+		ret = ltc_get_min(data, client, page, LTC2978_MFR_VIN_MIN,
+				  &data->vin_min);
+		break;
+	case PMBUS_VIRT_READ_VOUT_MIN:
+		ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
+		if (ret >= 0) {
+			/*
+			 * VOUT_MIN is known to not be supported on some lots
+			 * of LTC2978 revision 1, and will return the maximum
+			 * possible voltage if read. If VOUT_MAX is valid and
+			 * lower than the reading of VOUT_MIN, use it instead.
+			 */
+			if (data->vout_max[page] && ret > data->vout_max[page])
+				ret = data->vout_max[page];
+			if (ret < data->vout_min[page])
+				data->vout_min[page] = ret;
+			ret = data->vout_min[page];
+		}
+		break;
+	case PMBUS_VIRT_READ_TEMP_MIN:
+		ret = ltc_get_min(data, client, page,
+				  LTC2978_MFR_TEMPERATURE_MIN,
+				  &data->temp_min[page]);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MAX:
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+	case PMBUS_VIRT_READ_TEMP2_MAX:
+	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+		ret = -ENXIO;
+		break;
+	default:
+		ret = ltc2978_read_word_data_common(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = ltc_get_max(data, client, page, LTC2974_MFR_IOUT_PEAK,
+				  &data->iout_max[page]);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MIN:
+		ret = ltc_get_min(data, client, page, LTC2974_MFR_IOUT_MIN,
+				  &data->iout_min[page]);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = ltc2978_read_word_data(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_IIN_MAX:
+		ret = ltc_get_max(data, client, page, LTC2975_MFR_IIN_PEAK,
+				  &data->iin_max);
+		break;
+	case PMBUS_VIRT_READ_IIN_MIN:
+		ret = ltc_get_min(data, client, page, LTC2975_MFR_IIN_MIN,
+				  &data->iin_min);
+		break;
+	case PMBUS_VIRT_READ_PIN_MAX:
+		ret = ltc_get_max(data, client, page, LTC2975_MFR_PIN_PEAK,
+				  &data->pin_max);
+		break;
+	case PMBUS_VIRT_READ_PIN_MIN:
+		ret = ltc_get_min(data, client, page, LTC2975_MFR_PIN_MIN,
+				  &data->pin_min);
+		break;
+	case PMBUS_VIRT_RESET_IIN_HISTORY:
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = ltc2978_read_word_data(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = ltc_get_max(data, client, page, LTC3880_MFR_IOUT_PEAK,
+				  &data->iout_max[page]);
+		break;
+	case PMBUS_VIRT_READ_TEMP2_MAX:
+		ret = ltc_get_max(data, client, page,
+				  LTC3880_MFR_TEMPERATURE2_PEAK,
+				  &data->temp2_max);
+		break;
+	case PMBUS_VIRT_READ_VIN_MIN:
+	case PMBUS_VIRT_READ_VOUT_MIN:
+	case PMBUS_VIRT_READ_TEMP_MIN:
+		ret = -ENXIO;
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = ltc2978_read_word_data_common(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_IIN_MAX:
+		ret = ltc_get_max(data, client, page, LTC3883_MFR_IIN_PEAK,
+				  &data->iin_max);
+		break;
+	case PMBUS_VIRT_RESET_IIN_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = ltc3880_read_word_data(client, page, reg);
+		break;
+	}
+	return ret;
+}
+
+static int ltc2978_clear_peaks(struct ltc2978_data *data,
+			       struct i2c_client *client, int page)
+{
+	int ret;
+
+	if (has_clear_peaks(data))
+		ret = ltc_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
+	else
+		ret = ltc_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+
+	return ret;
+}
+
+static int ltc2978_write_word_data(struct i2c_client *client, int page,
+				    int reg, u16 word)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct ltc2978_data *data = to_ltc2978_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_RESET_IIN_HISTORY:
+		data->iin_max = 0x7c00;
+		data->iin_min = 0x7bff;
+		ret = ltc2978_clear_peaks(data, client, 0);
+		break;
+	case PMBUS_VIRT_RESET_PIN_HISTORY:
+		data->pin_max = 0x7c00;
+		data->pin_min = 0x7bff;
+		ret = ltc2978_clear_peaks(data, client, 0);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+		data->iout_max[page] = 0x7c00;
+		data->iout_min[page] = 0xfbff;
+		ret = ltc2978_clear_peaks(data, client, page);
+		break;
+	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+		data->temp2_max = 0x7c00;
+		ret = ltc2978_clear_peaks(data, client, page);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+		data->vout_min[page] = 0xffff;
+		data->vout_max[page] = 0;
+		ret = ltc2978_clear_peaks(data, client, page);
+		break;
+	case PMBUS_VIRT_RESET_VIN_HISTORY:
+		data->vin_min = 0x7bff;
+		data->vin_max = 0x7c00;
+		ret = ltc2978_clear_peaks(data, client, page);
+		break;
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		data->temp_min[page] = 0x7bff;
+		data->temp_max[page] = 0x7c00;
+		ret = ltc2978_clear_peaks(data, client, page);
+		break;
+	default:
+		ret = ltc_wait_ready(client);
+		if (ret < 0)
+			return ret;
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static const struct i2c_device_id ltc2978_id[] = {
+	{"ltc2974", ltc2974},
+	{"ltc2975", ltc2975},
+	{"ltc2977", ltc2977},
+	{"ltc2978", ltc2978},
+	{"ltc2980", ltc2980},
+	{"ltc3880", ltc3880},
+	{"ltc3882", ltc3882},
+	{"ltc3883", ltc3883},
+	{"ltc3886", ltc3886},
+	{"ltc3887", ltc3887},
+	{"ltm2987", ltm2987},
+	{"ltm4675", ltm4675},
+	{"ltm4676", ltm4676},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2978_id);
+
+#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
+static const struct regulator_desc ltc2978_reg_desc[] = {
+	PMBUS_REGULATOR("vout", 0),
+	PMBUS_REGULATOR("vout", 1),
+	PMBUS_REGULATOR("vout", 2),
+	PMBUS_REGULATOR("vout", 3),
+	PMBUS_REGULATOR("vout", 4),
+	PMBUS_REGULATOR("vout", 5),
+	PMBUS_REGULATOR("vout", 6),
+	PMBUS_REGULATOR("vout", 7),
+};
+#endif /* CONFIG_SENSORS_LTC2978_REGULATOR */
+
+static int ltc2978_get_id(struct i2c_client *client)
+{
+	int chip_id;
+
+	chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
+	if (chip_id < 0) {
+		const struct i2c_device_id *id;
+		u8 buf[I2C_SMBUS_BLOCK_MAX];
+		int ret;
+
+		if (!i2c_check_functionality(client->adapter,
+					     I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+			return -ENODEV;
+
+		ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+		if (ret < 0)
+			return ret;
+		if (ret < 3 || strncmp(buf, "LTC", 3))
+			return -ENODEV;
+
+		ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+		if (ret < 0)
+			return ret;
+		for (id = &ltc2978_id[0]; strlen(id->name); id++) {
+			if (!strncasecmp(id->name, buf, strlen(id->name)))
+				return (int)id->driver_data;
+		}
+		return -ENODEV;
+	}
+
+	chip_id &= LTC2978_ID_MASK;
+
+	if (chip_id == LTC2974_ID)
+		return ltc2974;
+	else if (chip_id == LTC2975_ID)
+		return ltc2975;
+	else if (chip_id == LTC2977_ID)
+		return ltc2977;
+	else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2)
+		return ltc2978;
+	else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B)
+		return ltc2980;
+	else if (chip_id == LTC3880_ID)
+		return ltc3880;
+	else if (chip_id == LTC3882_ID || chip_id == LTC3882_ID_D1)
+		return ltc3882;
+	else if (chip_id == LTC3883_ID)
+		return ltc3883;
+	else if (chip_id == LTC3886_ID)
+		return ltc3886;
+	else if (chip_id == LTC3887_ID)
+		return ltc3887;
+	else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B)
+		return ltm2987;
+	else if (chip_id == LTM4675_ID)
+		return ltm4675;
+	else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
+		 chip_id == LTM4676A_ID)
+		return ltm4676;
+
+	dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
+	return -ENODEV;
+}
+
+static int ltc2978_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int i, chip_id;
+	struct ltc2978_data *data;
+	struct pmbus_driver_info *info;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	chip_id = ltc2978_get_id(client);
+	if (chip_id < 0)
+		return chip_id;
+
+	data->id = chip_id;
+	if (data->id != id->driver_data)
+		dev_warn(&client->dev,
+			 "Device mismatch: Configured %s, detected %s\n",
+			 id->name,
+			 ltc2978_id[data->id].name);
+
+	info = &data->info;
+	info->write_word_data = ltc2978_write_word_data;
+	info->write_byte = ltc_write_byte;
+	info->read_word_data = ltc_read_word_data;
+	info->read_byte_data = ltc_read_byte_data;
+
+	data->vin_min = 0x7bff;
+	data->vin_max = 0x7c00;
+	for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
+		data->vout_min[i] = 0xffff;
+	for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
+		data->iout_min[i] = 0xfbff;
+	for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
+		data->iout_max[i] = 0x7c00;
+	for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
+		data->temp_min[i] = 0x7bff;
+	for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
+		data->temp_max[i] = 0x7c00;
+	data->temp2_max = 0x7c00;
+
+	switch (data->id) {
+	case ltc2974:
+		info->read_word_data = ltc2974_read_word_data;
+		info->pages = LTC2974_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+		  | PMBUS_HAVE_TEMP2;
+		for (i = 0; i < info->pages; i++) {
+			info->func[i] |= PMBUS_HAVE_VOUT
+			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
+			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+		}
+		break;
+	case ltc2975:
+		info->read_word_data = ltc2975_read_word_data;
+		info->pages = LTC2974_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
+		  | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+		  | PMBUS_HAVE_TEMP2;
+		for (i = 0; i < info->pages; i++) {
+			info->func[i] |= PMBUS_HAVE_VOUT
+			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
+			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+		}
+		break;
+	case ltc2977:
+	case ltc2978:
+	case ltc2980:
+	case ltm2987:
+		info->read_word_data = ltc2978_read_word_data;
+		info->pages = LTC2978_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+		for (i = 1; i < LTC2978_NUM_PAGES; i++) {
+			info->func[i] = PMBUS_HAVE_VOUT
+			  | PMBUS_HAVE_STATUS_VOUT;
+		}
+		break;
+	case ltc3880:
+	case ltc3887:
+	case ltm4675:
+	case ltm4676:
+		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
+		info->read_word_data = ltc3880_read_word_data;
+		info->pages = LTC3880_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+		  | PMBUS_HAVE_STATUS_INPUT
+		  | 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;
+		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+		  | PMBUS_HAVE_POUT
+		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+		break;
+	case ltc3882:
+		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
+		info->read_word_data = ltc3880_read_word_data;
+		info->pages = LTC3880_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN
+		  | PMBUS_HAVE_STATUS_INPUT
+		  | 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;
+		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+		  | PMBUS_HAVE_POUT
+		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+		break;
+	case ltc3883:
+		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
+		info->read_word_data = ltc3883_read_word_data;
+		info->pages = LTC3883_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+		  | PMBUS_HAVE_STATUS_INPUT
+		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+		  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+		break;
+	case ltc3886:
+		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
+		info->read_word_data = ltc3883_read_word_data;
+		info->pages = LTC3880_NUM_PAGES;
+		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+		  | PMBUS_HAVE_STATUS_INPUT
+		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+		  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+		  | PMBUS_HAVE_POUT
+		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
+	info->num_regulators = info->pages;
+	info->reg_desc = ltc2978_reg_desc;
+	if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
+		dev_err(&client->dev, "num_regulators too large!");
+		info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
+	}
+#endif
+
+	return pmbus_do_probe(client, id, info);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ltc2978_of_match[] = {
+	{ .compatible = "lltc,ltc2974" },
+	{ .compatible = "lltc,ltc2975" },
+	{ .compatible = "lltc,ltc2977" },
+	{ .compatible = "lltc,ltc2978" },
+	{ .compatible = "lltc,ltc2980" },
+	{ .compatible = "lltc,ltc3880" },
+	{ .compatible = "lltc,ltc3882" },
+	{ .compatible = "lltc,ltc3883" },
+	{ .compatible = "lltc,ltc3886" },
+	{ .compatible = "lltc,ltc3887" },
+	{ .compatible = "lltc,ltm2987" },
+	{ .compatible = "lltc,ltm4675" },
+	{ .compatible = "lltc,ltm4676" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ltc2978_of_match);
+#endif
+
+static struct i2c_driver ltc2978_driver = {
+	.driver = {
+		   .name = "ltc2978",
+		   .of_match_table = of_match_ptr(ltc2978_of_match),
+		   },
+	.probe = ltc2978_probe,
+	.remove = pmbus_do_remove,
+	.id_table = ltc2978_id,
+};
+
+module_i2c_driver(ltc2978_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LTC2978 and comppatible chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c
new file mode 100644
index 0000000..fa237a3
--- /dev/null
+++ b/drivers/hwmon/pmbus/max16064.c
@@ -0,0 +1,127 @@
+/*
+ * Hardware monitoring driver for Maxim MAX16064
+ *
+ * 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/i2c.h>
+#include "pmbus.h"
+
+#define MAX16064_MFR_VOUT_PEAK		0xd4
+#define MAX16064_MFR_TEMPERATURE_PEAK	0xd6
+
+static int max16064_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = pmbus_read_word_data(client, page,
+					   MAX16064_MFR_VOUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_TEMP_MAX:
+		ret = pmbus_read_word_data(client, page,
+					   MAX16064_MFR_TEMPERATURE_PEAK);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int max16064_write_word_data(struct i2c_client *client, int page,
+				    int reg, u16 word)
+{
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX16064_MFR_VOUT_PEAK, 0);
+		break;
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX16064_MFR_TEMPERATURE_PEAK,
+					    0xffff);
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static struct pmbus_driver_info max16064_info = {
+	.pages = 4,
+	.format[PSC_VOLTAGE_IN] = direct,
+	.format[PSC_VOLTAGE_OUT] = direct,
+	.format[PSC_TEMPERATURE] = direct,
+	.m[PSC_VOLTAGE_IN] = 19995,
+	.b[PSC_VOLTAGE_IN] = 0,
+	.R[PSC_VOLTAGE_IN] = -1,
+	.m[PSC_VOLTAGE_OUT] = 19995,
+	.b[PSC_VOLTAGE_OUT] = 0,
+	.R[PSC_VOLTAGE_OUT] = -1,
+	.m[PSC_TEMPERATURE] = -7612,
+	.b[PSC_TEMPERATURE] = 335,
+	.R[PSC_TEMPERATURE] = -3,
+	.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP
+		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP,
+	.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+	.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+	.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+	.read_word_data = max16064_read_word_data,
+	.write_word_data = max16064_write_word_data,
+};
+
+static int max16064_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	return pmbus_do_probe(client, id, &max16064_info);
+}
+
+static const struct i2c_device_id max16064_id[] = {
+	{"max16064", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, max16064_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max16064_driver = {
+	.driver = {
+		   .name = "max16064",
+		   },
+	.probe = max16064_probe,
+	.remove = pmbus_do_remove,
+	.id_table = max16064_id,
+};
+
+module_i2c_driver(max16064_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c
new file mode 100644
index 0000000..ab74aea
--- /dev/null
+++ b/drivers/hwmon/pmbus/max20751.c
@@ -0,0 +1,64 @@
+/*
+ * Hardware monitoring driver for Maxim MAX20751
+ *
+ * Copyright (c) 2015 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/i2c.h>
+#include "pmbus.h"
+
+static struct pmbus_driver_info max20751_info = {
+	.pages = 1,
+	.format[PSC_VOLTAGE_IN] = linear,
+	.format[PSC_VOLTAGE_OUT] = vid,
+	.vrm_version = vr12,
+	.format[PSC_TEMPERATURE] = linear,
+	.format[PSC_CURRENT_OUT] = linear,
+	.format[PSC_POWER] = linear,
+	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+		PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
+		PMBUS_HAVE_POUT,
+};
+
+static int max20751_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	return pmbus_do_probe(client, id, &max20751_info);
+}
+
+static const struct i2c_device_id max20751_id[] = {
+	{"max20751", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, max20751_id);
+
+static struct i2c_driver max20751_driver = {
+	.driver = {
+		   .name = "max20751",
+		   },
+	.probe = max20751_probe,
+	.remove = pmbus_do_remove,
+	.id_table = max20751_id,
+};
+
+module_i2c_driver(max20751_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
new file mode 100644
index 0000000..74a1f6f
--- /dev/null
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -0,0 +1,436 @@
+/*
+ * Hardware monitoring driver for Maxim MAX34440/MAX34441
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { max34440, max34441, max34446, max34460, max34461 };
+
+#define MAX34440_MFR_VOUT_PEAK		0xd4
+#define MAX34440_MFR_IOUT_PEAK		0xd5
+#define MAX34440_MFR_TEMPERATURE_PEAK	0xd6
+#define MAX34440_MFR_VOUT_MIN		0xd7
+
+#define MAX34446_MFR_POUT_PEAK		0xe0
+#define MAX34446_MFR_POUT_AVG		0xe1
+#define MAX34446_MFR_IOUT_AVG		0xe2
+#define MAX34446_MFR_TEMPERATURE_AVG	0xe3
+
+#define MAX34440_STATUS_OC_WARN		BIT(0)
+#define MAX34440_STATUS_OC_FAULT	BIT(1)
+#define MAX34440_STATUS_OT_FAULT	BIT(5)
+#define MAX34440_STATUS_OT_WARN		BIT(6)
+
+struct max34440_data {
+	int id;
+	struct pmbus_driver_info info;
+};
+
+#define to_max34440_data(x)  container_of(x, struct max34440_data, info)
+
+static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct max34440_data *data = to_max34440_data(info);
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VOUT_MIN:
+		ret = pmbus_read_word_data(client, page,
+					   MAX34440_MFR_VOUT_MIN);
+		break;
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = pmbus_read_word_data(client, page,
+					   MAX34440_MFR_VOUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_IOUT_AVG:
+		if (data->id != max34446)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, page,
+					   MAX34446_MFR_IOUT_AVG);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = pmbus_read_word_data(client, page,
+					   MAX34440_MFR_IOUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_POUT_AVG:
+		if (data->id != max34446)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, page,
+					   MAX34446_MFR_POUT_AVG);
+		break;
+	case PMBUS_VIRT_READ_POUT_MAX:
+		if (data->id != max34446)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, page,
+					   MAX34446_MFR_POUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_TEMP_AVG:
+		if (data->id != max34446 && data->id != max34460 &&
+		    data->id != max34461)
+			return -ENXIO;
+		ret = pmbus_read_word_data(client, page,
+					   MAX34446_MFR_TEMPERATURE_AVG);
+		break;
+	case PMBUS_VIRT_READ_TEMP_MAX:
+		ret = pmbus_read_word_data(client, page,
+					   MAX34440_MFR_TEMPERATURE_PEAK);
+		break;
+	case PMBUS_VIRT_RESET_POUT_HISTORY:
+		if (data->id != max34446)
+			return -ENXIO;
+		ret = 0;
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int max34440_write_word_data(struct i2c_client *client, int page,
+				    int reg, u16 word)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct max34440_data *data = to_max34440_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_RESET_POUT_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX34446_MFR_POUT_PEAK, 0);
+		if (ret)
+			break;
+		ret = pmbus_write_word_data(client, page,
+					    MAX34446_MFR_POUT_AVG, 0);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX34440_MFR_VOUT_MIN, 0x7fff);
+		if (ret)
+			break;
+		ret = pmbus_write_word_data(client, page,
+					    MAX34440_MFR_VOUT_PEAK, 0);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX34440_MFR_IOUT_PEAK, 0);
+		if (!ret && data->id == max34446)
+			ret = pmbus_write_word_data(client, page,
+					MAX34446_MFR_IOUT_AVG, 0);
+
+		break;
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = pmbus_write_word_data(client, page,
+					    MAX34440_MFR_TEMPERATURE_PEAK,
+					    0x8000);
+		if (!ret && data->id == max34446)
+			ret = pmbus_write_word_data(client, page,
+					MAX34446_MFR_TEMPERATURE_AVG, 0);
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	int ret = 0;
+	int mfg_status;
+
+	if (page >= 0) {
+		ret = pmbus_set_page(client, page);
+		if (ret < 0)
+			return ret;
+	}
+
+	switch (reg) {
+	case PMBUS_STATUS_IOUT:
+		mfg_status = pmbus_read_word_data(client, 0,
+						  PMBUS_STATUS_MFR_SPECIFIC);
+		if (mfg_status < 0)
+			return mfg_status;
+		if (mfg_status & MAX34440_STATUS_OC_WARN)
+			ret |= PB_IOUT_OC_WARNING;
+		if (mfg_status & MAX34440_STATUS_OC_FAULT)
+			ret |= PB_IOUT_OC_FAULT;
+		break;
+	case PMBUS_STATUS_TEMPERATURE:
+		mfg_status = pmbus_read_word_data(client, 0,
+						  PMBUS_STATUS_MFR_SPECIFIC);
+		if (mfg_status < 0)
+			return mfg_status;
+		if (mfg_status & MAX34440_STATUS_OT_WARN)
+			ret |= PB_TEMP_OT_WARNING;
+		if (mfg_status & MAX34440_STATUS_OT_FAULT)
+			ret |= PB_TEMP_OT_FAULT;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static struct pmbus_driver_info max34440_info[] = {
+	[max34440] = {
+		.pages = 14,
+		.format[PSC_VOLTAGE_IN] = direct,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.format[PSC_CURRENT_OUT] = direct,
+		.m[PSC_VOLTAGE_IN] = 1,
+		.b[PSC_VOLTAGE_IN] = 0,
+		.R[PSC_VOLTAGE_IN] = 3,	    /* R = 0 in datasheet reflects mV */
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,    /* R = 0 in datasheet reflects mV */
+		.m[PSC_CURRENT_OUT] = 1,
+		.b[PSC_CURRENT_OUT] = 0,
+		.R[PSC_CURRENT_OUT] = 3,    /* R = 0 in datasheet reflects mA */
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.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,
+		.func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+	[max34441] = {
+		.pages = 12,
+		.format[PSC_VOLTAGE_IN] = direct,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.format[PSC_CURRENT_OUT] = direct,
+		.format[PSC_FAN] = direct,
+		.m[PSC_VOLTAGE_IN] = 1,
+		.b[PSC_VOLTAGE_IN] = 0,
+		.R[PSC_VOLTAGE_IN] = 3,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_CURRENT_OUT] = 1,
+		.b[PSC_CURRENT_OUT] = 0,
+		.R[PSC_CURRENT_OUT] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.m[PSC_FAN] = 1,
+		.b[PSC_FAN] = 0,
+		.R[PSC_FAN] = 0,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
+		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.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,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+	[max34446] = {
+		.pages = 7,
+		.format[PSC_VOLTAGE_IN] = direct,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.format[PSC_CURRENT_OUT] = direct,
+		.format[PSC_POWER] = direct,
+		.m[PSC_VOLTAGE_IN] = 1,
+		.b[PSC_VOLTAGE_IN] = 0,
+		.R[PSC_VOLTAGE_IN] = 3,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_CURRENT_OUT] = 1,
+		.b[PSC_CURRENT_OUT] = 0,
+		.R[PSC_CURRENT_OUT] = 3,
+		.m[PSC_POWER] = 1,
+		.b[PSC_POWER] = 0,
+		.R[PSC_POWER] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+		.func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+	[max34460] = {
+		.pages = 18,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+	[max34461] = {
+		.pages = 23,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		/* page 16 is reserved */
+		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+};
+
+static int max34440_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct max34440_data *data;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct max34440_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	data->id = id->driver_data;
+	data->info = max34440_info[id->driver_data];
+
+	return pmbus_do_probe(client, id, &data->info);
+}
+
+static const struct i2c_device_id max34440_id[] = {
+	{"max34440", max34440},
+	{"max34441", max34441},
+	{"max34446", max34446},
+	{"max34460", max34460},
+	{"max34461", max34461},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, max34440_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max34440_driver = {
+	.driver = {
+		   .name = "max34440",
+		   },
+	.probe = max34440_probe,
+	.remove = pmbus_do_remove,
+	.id_table = max34440_id,
+};
+
+module_i2c_driver(max34440_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c
new file mode 100644
index 0000000..dd4883a
--- /dev/null
+++ b/drivers/hwmon/pmbus/max8688.c
@@ -0,0 +1,205 @@
+/*
+ * Hardware monitoring driver for Maxim MAX8688
+ *
+ * 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/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define MAX8688_MFR_VOUT_PEAK		0xd4
+#define MAX8688_MFR_IOUT_PEAK		0xd5
+#define MAX8688_MFR_TEMPERATURE_PEAK	0xd6
+#define MAX8688_MFG_STATUS		0xd8
+
+#define MAX8688_STATUS_OC_FAULT		BIT(4)
+#define MAX8688_STATUS_OV_FAULT		BIT(5)
+#define MAX8688_STATUS_OV_WARNING	BIT(8)
+#define MAX8688_STATUS_UV_FAULT		BIT(9)
+#define MAX8688_STATUS_UV_WARNING	BIT(10)
+#define MAX8688_STATUS_UC_FAULT		BIT(11)
+#define MAX8688_STATUS_OC_WARNING	BIT(12)
+#define MAX8688_STATUS_OT_FAULT		BIT(13)
+#define MAX8688_STATUS_OT_WARNING	BIT(14)
+
+static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	int ret;
+
+	if (page)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VOUT_MAX:
+		ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK);
+		break;
+	case PMBUS_VIRT_READ_TEMP_MAX:
+		ret = pmbus_read_word_data(client, 0,
+					   MAX8688_MFR_TEMPERATURE_PEAK);
+		break;
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int max8688_write_word_data(struct i2c_client *client, int page, int reg,
+				   u16 word)
+{
+	int ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_RESET_VOUT_HISTORY:
+		ret = pmbus_write_word_data(client, 0, MAX8688_MFR_VOUT_PEAK,
+					    0);
+		break;
+	case PMBUS_VIRT_RESET_IOUT_HISTORY:
+		ret = pmbus_write_word_data(client, 0, MAX8688_MFR_IOUT_PEAK,
+					    0);
+		break;
+	case PMBUS_VIRT_RESET_TEMP_HISTORY:
+		ret = pmbus_write_word_data(client, 0,
+					    MAX8688_MFR_TEMPERATURE_PEAK,
+					    0xffff);
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	int ret = 0;
+	int mfg_status;
+
+	if (page > 0)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_STATUS_VOUT:
+		mfg_status = pmbus_read_word_data(client, 0,
+						  MAX8688_MFG_STATUS);
+		if (mfg_status < 0)
+			return mfg_status;
+		if (mfg_status & MAX8688_STATUS_UV_WARNING)
+			ret |= PB_VOLTAGE_UV_WARNING;
+		if (mfg_status & MAX8688_STATUS_UV_FAULT)
+			ret |= PB_VOLTAGE_UV_FAULT;
+		if (mfg_status & MAX8688_STATUS_OV_WARNING)
+			ret |= PB_VOLTAGE_OV_WARNING;
+		if (mfg_status & MAX8688_STATUS_OV_FAULT)
+			ret |= PB_VOLTAGE_OV_FAULT;
+		break;
+	case PMBUS_STATUS_IOUT:
+		mfg_status = pmbus_read_word_data(client, 0,
+						  MAX8688_MFG_STATUS);
+		if (mfg_status < 0)
+			return mfg_status;
+		if (mfg_status & MAX8688_STATUS_UC_FAULT)
+			ret |= PB_IOUT_UC_FAULT;
+		if (mfg_status & MAX8688_STATUS_OC_WARNING)
+			ret |= PB_IOUT_OC_WARNING;
+		if (mfg_status & MAX8688_STATUS_OC_FAULT)
+			ret |= PB_IOUT_OC_FAULT;
+		break;
+	case PMBUS_STATUS_TEMPERATURE:
+		mfg_status = pmbus_read_word_data(client, 0,
+						  MAX8688_MFG_STATUS);
+		if (mfg_status < 0)
+			return mfg_status;
+		if (mfg_status & MAX8688_STATUS_OT_WARNING)
+			ret |= PB_TEMP_OT_WARNING;
+		if (mfg_status & MAX8688_STATUS_OT_FAULT)
+			ret |= PB_TEMP_OT_FAULT;
+		break;
+	default:
+		ret = -ENODATA;
+		break;
+	}
+	return ret;
+}
+
+static struct pmbus_driver_info max8688_info = {
+	.pages = 1,
+	.format[PSC_VOLTAGE_IN] = direct,
+	.format[PSC_VOLTAGE_OUT] = direct,
+	.format[PSC_TEMPERATURE] = direct,
+	.format[PSC_CURRENT_OUT] = direct,
+	.m[PSC_VOLTAGE_IN] = 19995,
+	.b[PSC_VOLTAGE_IN] = 0,
+	.R[PSC_VOLTAGE_IN] = -1,
+	.m[PSC_VOLTAGE_OUT] = 19995,
+	.b[PSC_VOLTAGE_OUT] = 0,
+	.R[PSC_VOLTAGE_OUT] = -1,
+	.m[PSC_CURRENT_OUT] = 23109,
+	.b[PSC_CURRENT_OUT] = 0,
+	.R[PSC_CURRENT_OUT] = -2,
+	.m[PSC_TEMPERATURE] = -7612,
+	.b[PSC_TEMPERATURE] = 335,
+	.R[PSC_TEMPERATURE] = -3,
+	.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
+		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+		| PMBUS_HAVE_STATUS_TEMP,
+	.read_byte_data = max8688_read_byte_data,
+	.read_word_data = max8688_read_word_data,
+	.write_word_data = max8688_write_word_data,
+};
+
+static int max8688_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	return pmbus_do_probe(client, id, &max8688_info);
+}
+
+static const struct i2c_device_id max8688_id[] = {
+	{"max8688", 0},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, max8688_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max8688_driver = {
+	.driver = {
+		   .name = "max8688",
+		   },
+	.probe = max8688_probe,
+	.remove = pmbus_do_remove,
+	.id_table = max8688_id,
+};
+
+module_i2c_driver(max8688_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
new file mode 100644
index 0000000..0a74991
--- /dev/null
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -0,0 +1,221 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 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/mutex.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+/*
+ * Find sensor groups and status registers on each page.
+ */
+static void pmbus_find_sensor_groups(struct i2c_client *client,
+				     struct pmbus_driver_info *info)
+{
+	int page;
+
+	/* Sensors detected on page 0 only */
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN))
+		info->func[0] |= PMBUS_HAVE_VIN;
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_VCAP))
+		info->func[0] |= PMBUS_HAVE_VCAP;
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_IIN))
+		info->func[0] |= PMBUS_HAVE_IIN;
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_PIN))
+		info->func[0] |= PMBUS_HAVE_PIN;
+	if (info->func[0]
+	    && pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
+		info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
+	if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) &&
+	    pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
+		info->func[0] |= PMBUS_HAVE_FAN12;
+		if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
+			info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
+	}
+	if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) &&
+	    pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
+		info->func[0] |= PMBUS_HAVE_FAN34;
+		if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
+			info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
+	}
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1))
+		info->func[0] |= PMBUS_HAVE_TEMP;
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2))
+		info->func[0] |= PMBUS_HAVE_TEMP2;
+	if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3))
+		info->func[0] |= PMBUS_HAVE_TEMP3;
+	if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
+			     | PMBUS_HAVE_TEMP3)
+	    && pmbus_check_byte_register(client, 0,
+					 PMBUS_STATUS_TEMPERATURE))
+			info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
+
+	/* Sensors detected on all pages */
+	for (page = 0; page < info->pages; page++) {
+		if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) {
+			info->func[page] |= PMBUS_HAVE_VOUT;
+			if (pmbus_check_byte_register(client, page,
+						      PMBUS_STATUS_VOUT))
+				info->func[page] |= PMBUS_HAVE_STATUS_VOUT;
+		}
+		if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) {
+			info->func[page] |= PMBUS_HAVE_IOUT;
+			if (pmbus_check_byte_register(client, 0,
+						      PMBUS_STATUS_IOUT))
+				info->func[page] |= PMBUS_HAVE_STATUS_IOUT;
+		}
+		if (pmbus_check_word_register(client, page, PMBUS_READ_POUT))
+			info->func[page] |= PMBUS_HAVE_POUT;
+	}
+}
+
+/*
+ * Identify chip parameters.
+ */
+static int pmbus_identify(struct i2c_client *client,
+			  struct pmbus_driver_info *info)
+{
+	int ret = 0;
+
+	if (!info->pages) {
+		/*
+		 * Check if the PAGE command is supported. If it is,
+		 * keep setting the page number until it fails or until the
+		 * maximum number of pages has been reached. Assume that
+		 * this is the number of pages supported by the chip.
+		 */
+		if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
+			int page;
+
+			for (page = 1; page < PMBUS_PAGES; page++) {
+				if (pmbus_set_page(client, page) < 0)
+					break;
+			}
+			pmbus_set_page(client, 0);
+			info->pages = page;
+		} else {
+			info->pages = 1;
+		}
+	}
+
+	if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
+		int vout_mode;
+
+		vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+		if (vout_mode >= 0 && vout_mode != 0xff) {
+			switch (vout_mode >> 5) {
+			case 0:
+				break;
+			case 1:
+				info->format[PSC_VOLTAGE_OUT] = vid;
+				info->vrm_version = vr11;
+				break;
+			case 2:
+				info->format[PSC_VOLTAGE_OUT] = direct;
+				break;
+			default:
+				ret = -ENODEV;
+				goto abort;
+			}
+		}
+	}
+
+	/*
+	 * We should check if the COEFFICIENTS register is supported.
+	 * If it is, and the chip is configured for direct mode, we can read
+	 * the coefficients from the chip, one set per group of sensor
+	 * registers.
+	 *
+	 * To do this, we will need access to a chip which actually supports the
+	 * COEFFICIENTS command, since the command is too complex to implement
+	 * without testing it. Until then, abort if a chip configured for direct
+	 * mode was detected.
+	 */
+	if (info->format[PSC_VOLTAGE_OUT] == direct) {
+		ret = -ENODEV;
+		goto abort;
+	}
+
+	/* Try to find sensor groups  */
+	pmbus_find_sensor_groups(client, info);
+abort:
+	return ret;
+}
+
+static int pmbus_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct pmbus_driver_info *info;
+
+	info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pages = id->driver_data;
+	info->identify = pmbus_identify;
+
+	return pmbus_do_probe(client, id, info);
+}
+
+/*
+ * Use driver_data to set the number of pages supported by the chip.
+ */
+static const struct i2c_device_id pmbus_id[] = {
+	{"adp4000", 1},
+	{"bmr453", 1},
+	{"bmr454", 1},
+	{"mdt040", 1},
+	{"ncp4200", 1},
+	{"ncp4208", 1},
+	{"pdt003", 1},
+	{"pdt006", 1},
+	{"pdt012", 1},
+	{"pmbus", 0},
+	{"tps40400", 1},
+	{"tps544b20", 1},
+	{"tps544b25", 1},
+	{"tps544c20", 1},
+	{"tps544c25", 1},
+	{"udt020", 1},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, pmbus_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pmbus_driver = {
+	.driver = {
+		   .name = "pmbus",
+		   },
+	.probe = pmbus_probe,
+	.remove = pmbus_do_remove,
+	.id_table = pmbus_id,
+};
+
+module_i2c_driver(pmbus_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Generic PMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
new file mode 100644
index 0000000..bfcb13b
--- /dev/null
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -0,0 +1,425 @@
+/*
+ * pmbus.h - Common defines and structures for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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.
+ */
+
+#ifndef PMBUS_H
+#define PMBUS_H
+
+#include <linux/bitops.h>
+#include <linux/regulator/driver.h>
+
+/*
+ * Registers
+ */
+enum pmbus_regs {
+	PMBUS_PAGE			= 0x00,
+	PMBUS_OPERATION			= 0x01,
+	PMBUS_ON_OFF_CONFIG		= 0x02,
+	PMBUS_CLEAR_FAULTS		= 0x03,
+	PMBUS_PHASE			= 0x04,
+
+	PMBUS_CAPABILITY		= 0x19,
+	PMBUS_QUERY			= 0x1A,
+
+	PMBUS_VOUT_MODE			= 0x20,
+	PMBUS_VOUT_COMMAND		= 0x21,
+	PMBUS_VOUT_TRIM			= 0x22,
+	PMBUS_VOUT_CAL_OFFSET		= 0x23,
+	PMBUS_VOUT_MAX			= 0x24,
+	PMBUS_VOUT_MARGIN_HIGH		= 0x25,
+	PMBUS_VOUT_MARGIN_LOW		= 0x26,
+	PMBUS_VOUT_TRANSITION_RATE	= 0x27,
+	PMBUS_VOUT_DROOP		= 0x28,
+	PMBUS_VOUT_SCALE_LOOP		= 0x29,
+	PMBUS_VOUT_SCALE_MONITOR	= 0x2A,
+
+	PMBUS_COEFFICIENTS		= 0x30,
+	PMBUS_POUT_MAX			= 0x31,
+
+	PMBUS_FAN_CONFIG_12		= 0x3A,
+	PMBUS_FAN_COMMAND_1		= 0x3B,
+	PMBUS_FAN_COMMAND_2		= 0x3C,
+	PMBUS_FAN_CONFIG_34		= 0x3D,
+	PMBUS_FAN_COMMAND_3		= 0x3E,
+	PMBUS_FAN_COMMAND_4		= 0x3F,
+
+	PMBUS_VOUT_OV_FAULT_LIMIT	= 0x40,
+	PMBUS_VOUT_OV_FAULT_RESPONSE	= 0x41,
+	PMBUS_VOUT_OV_WARN_LIMIT	= 0x42,
+	PMBUS_VOUT_UV_WARN_LIMIT	= 0x43,
+	PMBUS_VOUT_UV_FAULT_LIMIT	= 0x44,
+	PMBUS_VOUT_UV_FAULT_RESPONSE	= 0x45,
+	PMBUS_IOUT_OC_FAULT_LIMIT	= 0x46,
+	PMBUS_IOUT_OC_FAULT_RESPONSE	= 0x47,
+	PMBUS_IOUT_OC_LV_FAULT_LIMIT	= 0x48,
+	PMBUS_IOUT_OC_LV_FAULT_RESPONSE	= 0x49,
+	PMBUS_IOUT_OC_WARN_LIMIT	= 0x4A,
+	PMBUS_IOUT_UC_FAULT_LIMIT	= 0x4B,
+	PMBUS_IOUT_UC_FAULT_RESPONSE	= 0x4C,
+
+	PMBUS_OT_FAULT_LIMIT		= 0x4F,
+	PMBUS_OT_FAULT_RESPONSE		= 0x50,
+	PMBUS_OT_WARN_LIMIT		= 0x51,
+	PMBUS_UT_WARN_LIMIT		= 0x52,
+	PMBUS_UT_FAULT_LIMIT		= 0x53,
+	PMBUS_UT_FAULT_RESPONSE		= 0x54,
+	PMBUS_VIN_OV_FAULT_LIMIT	= 0x55,
+	PMBUS_VIN_OV_FAULT_RESPONSE	= 0x56,
+	PMBUS_VIN_OV_WARN_LIMIT		= 0x57,
+	PMBUS_VIN_UV_WARN_LIMIT		= 0x58,
+	PMBUS_VIN_UV_FAULT_LIMIT	= 0x59,
+
+	PMBUS_IIN_OC_FAULT_LIMIT	= 0x5B,
+	PMBUS_IIN_OC_WARN_LIMIT		= 0x5D,
+
+	PMBUS_POUT_OP_FAULT_LIMIT	= 0x68,
+	PMBUS_POUT_OP_WARN_LIMIT	= 0x6A,
+	PMBUS_PIN_OP_WARN_LIMIT		= 0x6B,
+
+	PMBUS_STATUS_BYTE		= 0x78,
+	PMBUS_STATUS_WORD		= 0x79,
+	PMBUS_STATUS_VOUT		= 0x7A,
+	PMBUS_STATUS_IOUT		= 0x7B,
+	PMBUS_STATUS_INPUT		= 0x7C,
+	PMBUS_STATUS_TEMPERATURE	= 0x7D,
+	PMBUS_STATUS_CML		= 0x7E,
+	PMBUS_STATUS_OTHER		= 0x7F,
+	PMBUS_STATUS_MFR_SPECIFIC	= 0x80,
+	PMBUS_STATUS_FAN_12		= 0x81,
+	PMBUS_STATUS_FAN_34		= 0x82,
+
+	PMBUS_READ_VIN			= 0x88,
+	PMBUS_READ_IIN			= 0x89,
+	PMBUS_READ_VCAP			= 0x8A,
+	PMBUS_READ_VOUT			= 0x8B,
+	PMBUS_READ_IOUT			= 0x8C,
+	PMBUS_READ_TEMPERATURE_1	= 0x8D,
+	PMBUS_READ_TEMPERATURE_2	= 0x8E,
+	PMBUS_READ_TEMPERATURE_3	= 0x8F,
+	PMBUS_READ_FAN_SPEED_1		= 0x90,
+	PMBUS_READ_FAN_SPEED_2		= 0x91,
+	PMBUS_READ_FAN_SPEED_3		= 0x92,
+	PMBUS_READ_FAN_SPEED_4		= 0x93,
+	PMBUS_READ_DUTY_CYCLE		= 0x94,
+	PMBUS_READ_FREQUENCY		= 0x95,
+	PMBUS_READ_POUT			= 0x96,
+	PMBUS_READ_PIN			= 0x97,
+
+	PMBUS_REVISION			= 0x98,
+	PMBUS_MFR_ID			= 0x99,
+	PMBUS_MFR_MODEL			= 0x9A,
+	PMBUS_MFR_REVISION		= 0x9B,
+	PMBUS_MFR_LOCATION		= 0x9C,
+	PMBUS_MFR_DATE			= 0x9D,
+	PMBUS_MFR_SERIAL		= 0x9E,
+
+/*
+ * Virtual registers.
+ * Useful to support attributes which are not supported by standard PMBus
+ * registers but exist as manufacturer specific registers on individual chips.
+ * Must be mapped to real registers in device specific code.
+ *
+ * Semantics:
+ * Virtual registers are all word size.
+ * READ registers are read-only; writes are either ignored or return an error.
+ * RESET registers are read/write. Reading reset registers returns zero
+ * (used for detection), writing any value causes the associated history to be
+ * reset.
+ * Virtual registers have to be handled in device specific driver code. Chip
+ * driver code returns non-negative register values if a virtual register is
+ * supported, or a negative error code if not. The chip driver may return
+ * -ENODATA or any other error code in this case, though an error code other
+ * than -ENODATA is handled more efficiently and thus preferred. Either case,
+ * the calling PMBus core code will abort if the chip driver returns an error
+ * code when reading or writing virtual registers.
+ */
+	PMBUS_VIRT_BASE			= 0x100,
+	PMBUS_VIRT_READ_TEMP_AVG,
+	PMBUS_VIRT_READ_TEMP_MIN,
+	PMBUS_VIRT_READ_TEMP_MAX,
+	PMBUS_VIRT_RESET_TEMP_HISTORY,
+	PMBUS_VIRT_READ_VIN_AVG,
+	PMBUS_VIRT_READ_VIN_MIN,
+	PMBUS_VIRT_READ_VIN_MAX,
+	PMBUS_VIRT_RESET_VIN_HISTORY,
+	PMBUS_VIRT_READ_IIN_AVG,
+	PMBUS_VIRT_READ_IIN_MIN,
+	PMBUS_VIRT_READ_IIN_MAX,
+	PMBUS_VIRT_RESET_IIN_HISTORY,
+	PMBUS_VIRT_READ_PIN_AVG,
+	PMBUS_VIRT_READ_PIN_MIN,
+	PMBUS_VIRT_READ_PIN_MAX,
+	PMBUS_VIRT_RESET_PIN_HISTORY,
+	PMBUS_VIRT_READ_POUT_AVG,
+	PMBUS_VIRT_READ_POUT_MIN,
+	PMBUS_VIRT_READ_POUT_MAX,
+	PMBUS_VIRT_RESET_POUT_HISTORY,
+	PMBUS_VIRT_READ_VOUT_AVG,
+	PMBUS_VIRT_READ_VOUT_MIN,
+	PMBUS_VIRT_READ_VOUT_MAX,
+	PMBUS_VIRT_RESET_VOUT_HISTORY,
+	PMBUS_VIRT_READ_IOUT_AVG,
+	PMBUS_VIRT_READ_IOUT_MIN,
+	PMBUS_VIRT_READ_IOUT_MAX,
+	PMBUS_VIRT_RESET_IOUT_HISTORY,
+	PMBUS_VIRT_READ_TEMP2_AVG,
+	PMBUS_VIRT_READ_TEMP2_MIN,
+	PMBUS_VIRT_READ_TEMP2_MAX,
+	PMBUS_VIRT_RESET_TEMP2_HISTORY,
+
+	PMBUS_VIRT_READ_VMON,
+	PMBUS_VIRT_VMON_UV_WARN_LIMIT,
+	PMBUS_VIRT_VMON_OV_WARN_LIMIT,
+	PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
+	PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
+	PMBUS_VIRT_STATUS_VMON,
+};
+
+/*
+ * OPERATION
+ */
+#define PB_OPERATION_CONTROL_ON		BIT(7)
+
+/*
+ * CAPABILITY
+ */
+#define PB_CAPABILITY_SMBALERT		BIT(4)
+#define PB_CAPABILITY_ERROR_CHECK	BIT(7)
+
+/*
+ * VOUT_MODE
+ */
+#define PB_VOUT_MODE_MODE_MASK		0xe0
+#define PB_VOUT_MODE_PARAM_MASK		0x1f
+
+#define PB_VOUT_MODE_LINEAR		0x00
+#define PB_VOUT_MODE_VID		0x20
+#define PB_VOUT_MODE_DIRECT		0x40
+
+/*
+ * Fan configuration
+ */
+#define PB_FAN_2_PULSE_MASK		(BIT(0) | BIT(1))
+#define PB_FAN_2_RPM			BIT(2)
+#define PB_FAN_2_INSTALLED		BIT(3)
+#define PB_FAN_1_PULSE_MASK		(BIT(4) | BIT(5))
+#define PB_FAN_1_RPM			BIT(6)
+#define PB_FAN_1_INSTALLED		BIT(7)
+
+/*
+ * STATUS_BYTE, STATUS_WORD (lower)
+ */
+#define PB_STATUS_NONE_ABOVE		BIT(0)
+#define PB_STATUS_CML			BIT(1)
+#define PB_STATUS_TEMPERATURE		BIT(2)
+#define PB_STATUS_VIN_UV		BIT(3)
+#define PB_STATUS_IOUT_OC		BIT(4)
+#define PB_STATUS_VOUT_OV		BIT(5)
+#define PB_STATUS_OFF			BIT(6)
+#define PB_STATUS_BUSY			BIT(7)
+
+/*
+ * STATUS_WORD (upper)
+ */
+#define PB_STATUS_UNKNOWN		BIT(8)
+#define PB_STATUS_OTHER			BIT(9)
+#define PB_STATUS_FANS			BIT(10)
+#define PB_STATUS_POWER_GOOD_N		BIT(11)
+#define PB_STATUS_WORD_MFR		BIT(12)
+#define PB_STATUS_INPUT			BIT(13)
+#define PB_STATUS_IOUT_POUT		BIT(14)
+#define PB_STATUS_VOUT			BIT(15)
+
+/*
+ * STATUS_IOUT
+ */
+#define PB_POUT_OP_WARNING		BIT(0)
+#define PB_POUT_OP_FAULT		BIT(1)
+#define PB_POWER_LIMITING		BIT(2)
+#define PB_CURRENT_SHARE_FAULT		BIT(3)
+#define PB_IOUT_UC_FAULT		BIT(4)
+#define PB_IOUT_OC_WARNING		BIT(5)
+#define PB_IOUT_OC_LV_FAULT		BIT(6)
+#define PB_IOUT_OC_FAULT		BIT(7)
+
+/*
+ * STATUS_VOUT, STATUS_INPUT
+ */
+#define PB_VOLTAGE_UV_FAULT		BIT(4)
+#define PB_VOLTAGE_UV_WARNING		BIT(5)
+#define PB_VOLTAGE_OV_WARNING		BIT(6)
+#define PB_VOLTAGE_OV_FAULT		BIT(7)
+
+/*
+ * STATUS_INPUT
+ */
+#define PB_PIN_OP_WARNING		BIT(0)
+#define PB_IIN_OC_WARNING		BIT(1)
+#define PB_IIN_OC_FAULT			BIT(2)
+
+/*
+ * STATUS_TEMPERATURE
+ */
+#define PB_TEMP_UT_FAULT		BIT(4)
+#define PB_TEMP_UT_WARNING		BIT(5)
+#define PB_TEMP_OT_WARNING		BIT(6)
+#define PB_TEMP_OT_FAULT		BIT(7)
+
+/*
+ * STATUS_FAN
+ */
+#define PB_FAN_AIRFLOW_WARNING		BIT(0)
+#define PB_FAN_AIRFLOW_FAULT		BIT(1)
+#define PB_FAN_FAN2_SPEED_OVERRIDE	BIT(2)
+#define PB_FAN_FAN1_SPEED_OVERRIDE	BIT(3)
+#define PB_FAN_FAN2_WARNING		BIT(4)
+#define PB_FAN_FAN1_WARNING		BIT(5)
+#define PB_FAN_FAN2_FAULT		BIT(6)
+#define PB_FAN_FAN1_FAULT		BIT(7)
+
+/*
+ * CML_FAULT_STATUS
+ */
+#define PB_CML_FAULT_OTHER_MEM_LOGIC	BIT(0)
+#define PB_CML_FAULT_OTHER_COMM		BIT(1)
+#define PB_CML_FAULT_PROCESSOR		BIT(3)
+#define PB_CML_FAULT_MEMORY		BIT(4)
+#define PB_CML_FAULT_PACKET_ERROR	BIT(5)
+#define PB_CML_FAULT_INVALID_DATA	BIT(6)
+#define PB_CML_FAULT_INVALID_COMMAND	BIT(7)
+
+enum pmbus_sensor_classes {
+	PSC_VOLTAGE_IN = 0,
+	PSC_VOLTAGE_OUT,
+	PSC_CURRENT_IN,
+	PSC_CURRENT_OUT,
+	PSC_POWER,
+	PSC_TEMPERATURE,
+	PSC_FAN,
+	PSC_NUM_CLASSES		/* Number of power sensor classes */
+};
+
+#define PMBUS_PAGES	32	/* Per PMBus specification */
+
+/* Functionality bit mask */
+#define PMBUS_HAVE_VIN		BIT(0)
+#define PMBUS_HAVE_VCAP		BIT(1)
+#define PMBUS_HAVE_VOUT		BIT(2)
+#define PMBUS_HAVE_IIN		BIT(3)
+#define PMBUS_HAVE_IOUT		BIT(4)
+#define PMBUS_HAVE_PIN		BIT(5)
+#define PMBUS_HAVE_POUT		BIT(6)
+#define PMBUS_HAVE_FAN12	BIT(7)
+#define PMBUS_HAVE_FAN34	BIT(8)
+#define PMBUS_HAVE_TEMP		BIT(9)
+#define PMBUS_HAVE_TEMP2	BIT(10)
+#define PMBUS_HAVE_TEMP3	BIT(11)
+#define PMBUS_HAVE_STATUS_VOUT	BIT(12)
+#define PMBUS_HAVE_STATUS_IOUT	BIT(13)
+#define PMBUS_HAVE_STATUS_INPUT	BIT(14)
+#define PMBUS_HAVE_STATUS_TEMP	BIT(15)
+#define PMBUS_HAVE_STATUS_FAN12	BIT(16)
+#define PMBUS_HAVE_STATUS_FAN34	BIT(17)
+#define PMBUS_HAVE_VMON		BIT(18)
+#define PMBUS_HAVE_STATUS_VMON	BIT(19)
+
+enum pmbus_data_format { linear = 0, direct, vid };
+enum vrm_version { vr11 = 0, vr12 };
+
+struct pmbus_driver_info {
+	int pages;		/* Total number of pages */
+	enum pmbus_data_format format[PSC_NUM_CLASSES];
+	enum vrm_version vrm_version;
+	/*
+	 * Support one set of coefficients for each sensor type
+	 * Used for chips providing data in direct mode.
+	 */
+	int m[PSC_NUM_CLASSES];	/* mantissa for direct data format */
+	int b[PSC_NUM_CLASSES];	/* offset */
+	int R[PSC_NUM_CLASSES];	/* exponent */
+
+	u32 func[PMBUS_PAGES];	/* Functionality, per page */
+	/*
+	 * The following functions map manufacturing specific register values
+	 * to PMBus standard register values. Specify only if mapping is
+	 * necessary.
+	 * Functions return the register value (read) or zero (write) if
+	 * successful. A return value of -ENODATA indicates that there is no
+	 * manufacturer specific register, but that a standard PMBus register
+	 * may exist. Any other negative return value indicates that the
+	 * register does not exist, and that no attempt should be made to read
+	 * the standard register.
+	 */
+	int (*read_byte_data)(struct i2c_client *client, int page, int reg);
+	int (*read_word_data)(struct i2c_client *client, int page, int reg);
+	int (*write_word_data)(struct i2c_client *client, int page, int reg,
+			       u16 word);
+	int (*write_byte)(struct i2c_client *client, int page, u8 value);
+	/*
+	 * The identify function determines supported PMBus functionality.
+	 * This function is only necessary if a chip driver supports multiple
+	 * chips, and the chip functionality is not pre-determined.
+	 */
+	int (*identify)(struct i2c_client *client,
+			struct pmbus_driver_info *info);
+
+	/* Regulator functionality, if supported by this chip driver. */
+	int num_regulators;
+	const struct regulator_desc *reg_desc;
+};
+
+/* Regulator ops */
+
+extern const struct regulator_ops pmbus_regulator_ops;
+
+/* Macro for filling in array of struct regulator_desc */
+#define PMBUS_REGULATOR(_name, _id)				\
+	[_id] = {						\
+		.name = (_name # _id),				\
+		.id = (_id),					\
+		.of_match = of_match_ptr(_name # _id),		\
+		.regulators_node = of_match_ptr("regulators"),	\
+		.ops = &pmbus_regulator_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.owner = THIS_MODULE,				\
+	}
+
+/* Function declarations */
+
+void pmbus_clear_cache(struct i2c_client *client);
+int pmbus_set_page(struct i2c_client *client, u8 page);
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
+int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
+			  u8 value);
+int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
+			   u8 mask, u8 value);
+void pmbus_clear_faults(struct i2c_client *client);
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+		   struct pmbus_driver_info *info);
+int pmbus_do_remove(struct i2c_client *client);
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
+						      *client);
+
+#endif /* PMBUS_H */
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
new file mode 100644
index 0000000..ba59eae
--- /dev/null
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -0,0 +1,1942 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/i2c/pmbus.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include "pmbus.h"
+
+/*
+ * Number of additional attribute pointers to allocate
+ * with each call to krealloc
+ */
+#define PMBUS_ATTR_ALLOC_SIZE	32
+
+/*
+ * Index into status register array, per status register group
+ */
+#define PB_STATUS_BASE		0
+#define PB_STATUS_VOUT_BASE	(PB_STATUS_BASE + PMBUS_PAGES)
+#define PB_STATUS_IOUT_BASE	(PB_STATUS_VOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN_BASE	(PB_STATUS_IOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN34_BASE	(PB_STATUS_FAN_BASE + PMBUS_PAGES)
+#define PB_STATUS_TEMP_BASE	(PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE	(PB_STATUS_TEMP_BASE + PMBUS_PAGES)
+#define PB_STATUS_VMON_BASE	(PB_STATUS_INPUT_BASE + 1)
+
+#define PB_NUM_STATUS_REG	(PB_STATUS_VMON_BASE + 1)
+
+#define PMBUS_NAME_SIZE		24
+
+struct pmbus_sensor {
+	struct pmbus_sensor *next;
+	char name[PMBUS_NAME_SIZE];	/* sysfs sensor name */
+	struct device_attribute attribute;
+	u8 page;		/* page number */
+	u16 reg;		/* register */
+	enum pmbus_sensor_classes class;	/* sensor class */
+	bool update;		/* runtime sensor update needed */
+	int data;		/* Sensor data.
+				   Negative if there was a read error */
+};
+#define to_pmbus_sensor(_attr) \
+	container_of(_attr, struct pmbus_sensor, attribute)
+
+struct pmbus_boolean {
+	char name[PMBUS_NAME_SIZE];	/* sysfs boolean name */
+	struct sensor_device_attribute attribute;
+	struct pmbus_sensor *s1;
+	struct pmbus_sensor *s2;
+};
+#define to_pmbus_boolean(_attr) \
+	container_of(_attr, struct pmbus_boolean, attribute)
+
+struct pmbus_label {
+	char name[PMBUS_NAME_SIZE];	/* sysfs label name */
+	struct device_attribute attribute;
+	char label[PMBUS_NAME_SIZE];	/* label */
+};
+#define to_pmbus_label(_attr) \
+	container_of(_attr, struct pmbus_label, attribute)
+
+struct pmbus_data {
+	struct device *dev;
+	struct device *hwmon_dev;
+
+	u32 flags;		/* from platform data */
+
+	int exponent[PMBUS_PAGES];
+				/* linear mode: exponent for output voltages */
+
+	const struct pmbus_driver_info *info;
+
+	int max_attributes;
+	int num_attributes;
+	struct attribute_group group;
+	const struct attribute_group *groups[2];
+
+	struct pmbus_sensor *sensors;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+
+	/*
+	 * A single status register covers multiple attributes,
+	 * so we keep them all together.
+	 */
+	u8 status[PB_NUM_STATUS_REG];
+	u8 status_register;
+
+	u8 currpage;
+};
+
+void pmbus_clear_cache(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+
+	data->valid = false;
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_cache);
+
+int pmbus_set_page(struct i2c_client *client, u8 page)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	int rv = 0;
+	int newpage;
+
+	if (page != data->currpage) {
+		rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+		newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
+		if (newpage != page)
+			rv = -EIO;
+		else
+			data->currpage = page;
+	}
+	return rv;
+}
+EXPORT_SYMBOL_GPL(pmbus_set_page);
+
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
+{
+	int rv;
+
+	if (page >= 0) {
+		rv = pmbus_set_page(client, page);
+		if (rv < 0)
+			return rv;
+	}
+
+	return i2c_smbus_write_byte(client, value);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_byte);
+
+/*
+ * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	const struct pmbus_driver_info *info = data->info;
+	int status;
+
+	if (info->write_byte) {
+		status = info->write_byte(client, page, value);
+		if (status != -ENODATA)
+			return status;
+	}
+	return pmbus_write_byte(client, page, value);
+}
+
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
+{
+	int rv;
+
+	rv = pmbus_set_page(client, page);
+	if (rv < 0)
+		return rv;
+
+	return i2c_smbus_write_word_data(client, reg, word);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_word_data);
+
+/*
+ * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
+				  u16 word)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	const struct pmbus_driver_info *info = data->info;
+	int status;
+
+	if (info->write_word_data) {
+		status = info->write_word_data(client, page, reg, word);
+		if (status != -ENODATA)
+			return status;
+	}
+	if (reg >= PMBUS_VIRT_BASE)
+		return -ENXIO;
+	return pmbus_write_word_data(client, page, reg, word);
+}
+
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
+{
+	int rv;
+
+	rv = pmbus_set_page(client, page);
+	if (rv < 0)
+		return rv;
+
+	return i2c_smbus_read_word_data(client, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_read_word_data);
+
+/*
+ * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_read_word_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->read_word_data) {
+		status = info->read_word_data(client, page, reg);
+		if (status != -ENODATA)
+			return status;
+	}
+	if (reg >= PMBUS_VIRT_BASE)
+		return -ENXIO;
+	return pmbus_read_word_data(client, page, reg);
+}
+
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
+{
+	int rv;
+
+	if (page >= 0) {
+		rv = pmbus_set_page(client, page);
+		if (rv < 0)
+			return rv;
+	}
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
+
+int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
+{
+	int rv;
+
+	rv = pmbus_set_page(client, page);
+	if (rv < 0)
+		return rv;
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_byte_data);
+
+int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
+			   u8 mask, u8 value)
+{
+	unsigned int tmp;
+	int rv;
+
+	rv = pmbus_read_byte_data(client, page, reg);
+	if (rv < 0)
+		return rv;
+
+	tmp = (rv & ~mask) | (value & mask);
+
+	if (tmp != rv)
+		rv = pmbus_write_byte_data(client, page, reg, tmp);
+
+	return rv;
+}
+EXPORT_SYMBOL_GPL(pmbus_update_byte_data);
+
+/*
+ * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
+ * a device specific mapping function 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->read_byte_data) {
+		status = info->read_byte_data(client, page, reg);
+		if (status != -ENODATA)
+			return status;
+	}
+	return pmbus_read_byte_data(client, page, reg);
+}
+
+static void pmbus_clear_fault_page(struct i2c_client *client, int page)
+{
+	_pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+}
+
+void pmbus_clear_faults(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < data->info->pages; i++)
+		pmbus_clear_fault_page(client, i);
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_faults);
+
+static int pmbus_check_status_cml(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	int status, status2;
+
+	status = _pmbus_read_byte_data(client, -1, data->status_register);
+	if (status < 0 || (status & PB_STATUS_CML)) {
+		status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
+		if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
+			return -EIO;
+	}
+	return 0;
+}
+
+static bool pmbus_check_register(struct i2c_client *client,
+				 int (*func)(struct i2c_client *client,
+					     int page, int reg),
+				 int page, int reg)
+{
+	int rv;
+	struct pmbus_data *data = i2c_get_clientdata(client);
+
+	rv = func(client, page, reg);
+	if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+		rv = pmbus_check_status_cml(client);
+	pmbus_clear_fault_page(client, -1);
+	return rv >= 0;
+}
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+	return pmbus_check_register(client, _pmbus_read_byte_data, page, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
+
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
+{
+	return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_check_word_register);
+
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+
+	return data->info;
+}
+EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
+
+static struct _pmbus_status {
+	u32 func;
+	u16 base;
+	u16 reg;
+} pmbus_status[] = {
+	{ PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT },
+	{ PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT },
+	{ PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE,
+	  PMBUS_STATUS_TEMPERATURE },
+	{ PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 },
+	{ PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 },
+};
+
+static struct pmbus_data *pmbus_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	const struct pmbus_driver_info *info = data->info;
+	struct pmbus_sensor *sensor;
+
+	mutex_lock(&data->update_lock);
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		int i, j;
+
+		for (i = 0; i < info->pages; i++) {
+			data->status[PB_STATUS_BASE + i]
+			    = _pmbus_read_byte_data(client, i,
+						    data->status_register);
+			for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) {
+				struct _pmbus_status *s = &pmbus_status[j];
+
+				if (!(info->func[i] & s->func))
+					continue;
+				data->status[s->base + i]
+					= _pmbus_read_byte_data(client, i,
+								s->reg);
+			}
+		}
+
+		if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
+			data->status[PB_STATUS_INPUT_BASE]
+			  = _pmbus_read_byte_data(client, 0,
+						  PMBUS_STATUS_INPUT);
+
+		if (info->func[0] & PMBUS_HAVE_STATUS_VMON)
+			data->status[PB_STATUS_VMON_BASE]
+			  = _pmbus_read_byte_data(client, 0,
+						  PMBUS_VIRT_STATUS_VMON);
+
+		for (sensor = data->sensors; sensor; sensor = sensor->next) {
+			if (!data->valid || sensor->update)
+				sensor->data
+				    = _pmbus_read_word_data(client,
+							    sensor->page,
+							    sensor->reg);
+		}
+		pmbus_clear_faults(client);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Convert linear sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static long pmbus_reg2data_linear(struct pmbus_data *data,
+				  struct pmbus_sensor *sensor)
+{
+	s16 exponent;
+	s32 mantissa;
+	long val;
+
+	if (sensor->class == PSC_VOLTAGE_OUT) {	/* LINEAR16 */
+		exponent = data->exponent[sensor->page];
+		mantissa = (u16) sensor->data;
+	} else {				/* LINEAR11 */
+		exponent = ((s16)sensor->data) >> 11;
+		mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5;
+	}
+
+	val = mantissa;
+
+	/* scale result to milli-units for all sensors except fans */
+	if (sensor->class != PSC_FAN)
+		val = val * 1000L;
+
+	/* scale result to micro-units for power sensors */
+	if (sensor->class == PSC_POWER)
+		val = val * 1000L;
+
+	if (exponent >= 0)
+		val <<= exponent;
+	else
+		val >>= -exponent;
+
+	return val;
+}
+
+/*
+ * Convert direct sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static long pmbus_reg2data_direct(struct pmbus_data *data,
+				  struct pmbus_sensor *sensor)
+{
+	long val = (s16) sensor->data;
+	long m, b, R;
+
+	m = data->info->m[sensor->class];
+	b = data->info->b[sensor->class];
+	R = data->info->R[sensor->class];
+
+	if (m == 0)
+		return 0;
+
+	/* X = 1/m * (Y * 10^-R - b) */
+	R = -R;
+	/* scale result to milli-units for everything but fans */
+	if (sensor->class != PSC_FAN) {
+		R += 3;
+		b *= 1000;
+	}
+
+	/* scale result to micro-units for power sensors */
+	if (sensor->class == PSC_POWER) {
+		R += 3;
+		b *= 1000;
+	}
+
+	while (R > 0) {
+		val *= 10;
+		R--;
+	}
+	while (R < 0) {
+		val = DIV_ROUND_CLOSEST(val, 10);
+		R++;
+	}
+
+	return (val - b) / m;
+}
+
+/*
+ * Convert VID sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static long pmbus_reg2data_vid(struct pmbus_data *data,
+			       struct pmbus_sensor *sensor)
+{
+	long val = sensor->data;
+	long rv = 0;
+
+	switch (data->info->vrm_version) {
+	case vr11:
+		if (val >= 0x02 && val <= 0xb2)
+			rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100);
+		break;
+	case vr12:
+		if (val >= 0x01)
+			rv = 250 + (val - 1) * 5;
+		break;
+	}
+	return rv;
+}
+
+static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
+{
+	long val;
+
+	switch (data->info->format[sensor->class]) {
+	case direct:
+		val = pmbus_reg2data_direct(data, sensor);
+		break;
+	case vid:
+		val = pmbus_reg2data_vid(data, sensor);
+		break;
+	case linear:
+	default:
+		val = pmbus_reg2data_linear(data, sensor);
+		break;
+	}
+	return val;
+}
+
+#define MAX_MANTISSA	(1023 * 1000)
+#define MIN_MANTISSA	(511 * 1000)
+
+static u16 pmbus_data2reg_linear(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor, long val)
+{
+	s16 exponent = 0, mantissa;
+	bool negative = false;
+
+	/* simple case */
+	if (val == 0)
+		return 0;
+
+	if (sensor->class == PSC_VOLTAGE_OUT) {
+		/* LINEAR16 does not support negative voltages */
+		if (val < 0)
+			return 0;
+
+		/*
+		 * For a static exponents, we don't have a choice
+		 * but to adjust the value to it.
+		 */
+		if (data->exponent[sensor->page] < 0)
+			val <<= -data->exponent[sensor->page];
+		else
+			val >>= data->exponent[sensor->page];
+		val = DIV_ROUND_CLOSEST(val, 1000);
+		return val & 0xffff;
+	}
+
+	if (val < 0) {
+		negative = true;
+		val = -val;
+	}
+
+	/* Power is in uW. Convert to mW before converting. */
+	if (sensor->class == PSC_POWER)
+		val = DIV_ROUND_CLOSEST(val, 1000L);
+
+	/*
+	 * For simplicity, convert fan data to milli-units
+	 * before calculating the exponent.
+	 */
+	if (sensor->class == PSC_FAN)
+		val = val * 1000;
+
+	/* Reduce large mantissa until it fits into 10 bit */
+	while (val >= MAX_MANTISSA && exponent < 15) {
+		exponent++;
+		val >>= 1;
+	}
+	/* Increase small mantissa to improve precision */
+	while (val < MIN_MANTISSA && exponent > -15) {
+		exponent--;
+		val <<= 1;
+	}
+
+	/* Convert mantissa from milli-units to units */
+	mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+	/* Ensure that resulting number is within range */
+	if (mantissa > 0x3ff)
+		mantissa = 0x3ff;
+
+	/* restore sign */
+	if (negative)
+		mantissa = -mantissa;
+
+	/* Convert to 5 bit exponent, 11 bit mantissa */
+	return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
+static u16 pmbus_data2reg_direct(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor, long val)
+{
+	long m, b, R;
+
+	m = data->info->m[sensor->class];
+	b = data->info->b[sensor->class];
+	R = data->info->R[sensor->class];
+
+	/* Power is in uW. Adjust R and b. */
+	if (sensor->class == PSC_POWER) {
+		R -= 3;
+		b *= 1000;
+	}
+
+	/* Calculate Y = (m * X + b) * 10^R */
+	if (sensor->class != PSC_FAN) {
+		R -= 3;		/* Adjust R and b for data in milli-units */
+		b *= 1000;
+	}
+	val = val * m + b;
+
+	while (R > 0) {
+		val *= 10;
+		R--;
+	}
+	while (R < 0) {
+		val = DIV_ROUND_CLOSEST(val, 10);
+		R++;
+	}
+
+	return val;
+}
+
+static u16 pmbus_data2reg_vid(struct pmbus_data *data,
+			      struct pmbus_sensor *sensor, long val)
+{
+	val = clamp_val(val, 500, 1600);
+
+	return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
+}
+
+static u16 pmbus_data2reg(struct pmbus_data *data,
+			  struct pmbus_sensor *sensor, long val)
+{
+	u16 regval;
+
+	switch (data->info->format[sensor->class]) {
+	case direct:
+		regval = pmbus_data2reg_direct(data, sensor, val);
+		break;
+	case vid:
+		regval = pmbus_data2reg_vid(data, sensor, val);
+		break;
+	case linear:
+	default:
+		regval = pmbus_data2reg_linear(data, sensor, val);
+		break;
+	}
+	return regval;
+}
+
+/*
+ * Return boolean calculated from converted data.
+ * <index> defines a status register index and mask.
+ * The mask is in the lower 8 bits, the register index is in bits 8..23.
+ *
+ * The associated pmbus_boolean structure contains optional pointers to two
+ * sensor attributes. If specified, those attributes are compared against each
+ * other to determine if a limit has been exceeded.
+ *
+ * If the sensor attribute pointers are NULL, the function returns true if
+ * (status[reg] & mask) is true.
+ *
+ * If sensor attribute pointers are provided, a comparison against a specified
+ * limit has to be performed to determine the boolean result.
+ * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
+ * sensor values referenced by sensor attribute pointers s1 and s2).
+ *
+ * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
+ * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
+ *
+ * If a negative value is stored in any of the referenced registers, this value
+ * reflects an error code which will be returned.
+ */
+static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,
+			     int index)
+{
+	struct pmbus_sensor *s1 = b->s1;
+	struct pmbus_sensor *s2 = b->s2;
+	u16 reg = (index >> 8) & 0xffff;
+	u8 mask = index & 0xff;
+	int ret, status;
+	u8 regval;
+
+	status = data->status[reg];
+	if (status < 0)
+		return status;
+
+	regval = status & mask;
+	if (!s1 && !s2) {
+		ret = !!regval;
+	} else if (!s1 || !s2) {
+		WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2);
+		return 0;
+	} else {
+		long v1, v2;
+
+		if (s1->data < 0)
+			return s1->data;
+		if (s2->data < 0)
+			return s2->data;
+
+		v1 = pmbus_reg2data(data, s1);
+		v2 = pmbus_reg2data(data, s2);
+		ret = !!(regval && v1 >= v2);
+	}
+	return ret;
+}
+
+static ssize_t pmbus_show_boolean(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pmbus_boolean *boolean = to_pmbus_boolean(attr);
+	struct pmbus_data *data = pmbus_update_device(dev);
+	int val;
+
+	val = pmbus_get_boolean(data, boolean, attr->index);
+	if (val < 0)
+		return val;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t pmbus_show_sensor(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct pmbus_data *data = pmbus_update_device(dev);
+	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+
+	if (sensor->data < 0)
+		return sensor->data;
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor));
+}
+
+static ssize_t pmbus_set_sensor(struct device *dev,
+				struct device_attribute *devattr,
+				const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+	ssize_t rv = count;
+	long val = 0;
+	int ret;
+	u16 regval;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	regval = pmbus_data2reg(data, sensor, val);
+	ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
+	if (ret < 0)
+		rv = ret;
+	else
+		sensor->data = regval;
+	mutex_unlock(&data->update_lock);
+	return rv;
+}
+
+static ssize_t pmbus_show_label(struct device *dev,
+				struct device_attribute *da, char *buf)
+{
+	struct pmbus_label *label = to_pmbus_label(da);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
+}
+
+static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
+{
+	if (data->num_attributes >= data->max_attributes - 1) {
+		int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE;
+		void *new_attrs = krealloc(data->group.attrs,
+					   new_max_attrs * sizeof(void *),
+					   GFP_KERNEL);
+		if (!new_attrs)
+			return -ENOMEM;
+		data->group.attrs = new_attrs;
+		data->max_attributes = new_max_attrs;
+	}
+
+	data->group.attrs[data->num_attributes++] = attr;
+	data->group.attrs[data->num_attributes] = NULL;
+	return 0;
+}
+
+static void pmbus_dev_attr_init(struct device_attribute *dev_attr,
+				const char *name,
+				umode_t mode,
+				ssize_t (*show)(struct device *dev,
+						struct device_attribute *attr,
+						char *buf),
+				ssize_t (*store)(struct device *dev,
+						 struct device_attribute *attr,
+						 const char *buf, size_t count))
+{
+	sysfs_attr_init(&dev_attr->attr);
+	dev_attr->attr.name = name;
+	dev_attr->attr.mode = mode;
+	dev_attr->show = show;
+	dev_attr->store = store;
+}
+
+static void pmbus_attr_init(struct sensor_device_attribute *a,
+			    const char *name,
+			    umode_t mode,
+			    ssize_t (*show)(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf),
+			    ssize_t (*store)(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count),
+			    int idx)
+{
+	pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store);
+	a->index = idx;
+}
+
+static int pmbus_add_boolean(struct pmbus_data *data,
+			     const char *name, const char *type, int seq,
+			     struct pmbus_sensor *s1,
+			     struct pmbus_sensor *s2,
+			     u16 reg, u8 mask)
+{
+	struct pmbus_boolean *boolean;
+	struct sensor_device_attribute *a;
+
+	boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL);
+	if (!boolean)
+		return -ENOMEM;
+
+	a = &boolean->attribute;
+
+	snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
+		 name, seq, type);
+	boolean->s1 = s1;
+	boolean->s2 = s2;
+	pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL,
+			(reg << 8) | mask);
+
+	return pmbus_add_attribute(data, &a->dev_attr.attr);
+}
+
+static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+					     const char *name, const char *type,
+					     int seq, int page, int reg,
+					     enum pmbus_sensor_classes class,
+					     bool update, bool readonly)
+{
+	struct pmbus_sensor *sensor;
+	struct device_attribute *a;
+
+	sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return NULL;
+	a = &sensor->attribute;
+
+	snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
+		 name, seq, type);
+	sensor->page = page;
+	sensor->reg = reg;
+	sensor->class = class;
+	sensor->update = update;
+	pmbus_dev_attr_init(a, sensor->name,
+			    readonly ? S_IRUGO : S_IRUGO | S_IWUSR,
+			    pmbus_show_sensor, pmbus_set_sensor);
+
+	if (pmbus_add_attribute(data, &a->attr))
+		return NULL;
+
+	sensor->next = data->sensors;
+	data->sensors = sensor;
+
+	return sensor;
+}
+
+static int pmbus_add_label(struct pmbus_data *data,
+			   const char *name, int seq,
+			   const char *lstring, int index)
+{
+	struct pmbus_label *label;
+	struct device_attribute *a;
+
+	label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+	if (!label)
+		return -ENOMEM;
+
+	a = &label->attribute;
+
+	snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
+	if (!index)
+		strncpy(label->label, lstring, sizeof(label->label) - 1);
+	else
+		snprintf(label->label, sizeof(label->label), "%s%d", lstring,
+			 index);
+
+	pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL);
+	return pmbus_add_attribute(data, &a->attr);
+}
+
+/*
+ * Search for attributes. Allocate sensors, booleans, and labels as needed.
+ */
+
+/*
+ * The pmbus_limit_attr structure describes a single limit attribute
+ * and its associated alarm attribute.
+ */
+struct pmbus_limit_attr {
+	u16 reg;		/* Limit register */
+	u16 sbit;		/* Alarm attribute status bit */
+	bool update;		/* True if register needs updates */
+	bool low;		/* True if low limit; for limits with compare
+				   functions only */
+	const char *attr;	/* Attribute name */
+	const char *alarm;	/* Alarm attribute name */
+};
+
+/*
+ * The pmbus_sensor_attr structure describes one sensor attribute. This
+ * description includes a reference to the associated limit attributes.
+ */
+struct pmbus_sensor_attr {
+	u16 reg;			/* sensor register */
+	u8 gbit;			/* generic status bit */
+	u8 nlimit;			/* # of limit registers */
+	enum pmbus_sensor_classes class;/* sensor class */
+	const char *label;		/* sensor label */
+	bool paged;			/* true if paged sensor */
+	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 */
+	const struct pmbus_limit_attr *limit;/* limit registers */
+};
+
+/*
+ * Add a set of limit attributes and, if supported, the associated
+ * alarm attributes.
+ * returns 0 if no alarm register found, 1 if an alarm register was found,
+ * < 0 on errors.
+ */
+static int pmbus_add_limit_attrs(struct i2c_client *client,
+				 struct pmbus_data *data,
+				 const struct pmbus_driver_info *info,
+				 const char *name, int index, int page,
+				 struct pmbus_sensor *base,
+				 const struct pmbus_sensor_attr *attr)
+{
+	const struct pmbus_limit_attr *l = attr->limit;
+	int nlimit = attr->nlimit;
+	int have_alarm = 0;
+	int i, ret;
+	struct pmbus_sensor *curr;
+
+	for (i = 0; i < nlimit; i++) {
+		if (pmbus_check_word_register(client, page, l->reg)) {
+			curr = pmbus_add_sensor(data, name, l->attr, index,
+						page, l->reg, attr->class,
+						attr->update || l->update,
+						false);
+			if (!curr)
+				return -ENOMEM;
+			if (l->sbit && (info->func[page] & attr->sfunc)) {
+				ret = pmbus_add_boolean(data, name,
+					l->alarm, index,
+					attr->compare ?  l->low ? curr : base
+						      : NULL,
+					attr->compare ? l->low ? base : curr
+						      : NULL,
+					attr->sbase + page, l->sbit);
+				if (ret)
+					return ret;
+				have_alarm = 1;
+			}
+		}
+		l++;
+	}
+	return have_alarm;
+}
+
+static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+				      struct pmbus_data *data,
+				      const struct pmbus_driver_info *info,
+				      const char *name,
+				      int index, int page,
+				      const struct pmbus_sensor_attr *attr)
+{
+	struct pmbus_sensor *base;
+	int ret;
+
+	if (attr->label) {
+		ret = pmbus_add_label(data, name, index, attr->label,
+				      attr->paged ? page + 1 : 0);
+		if (ret)
+			return ret;
+	}
+	base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+				attr->class, true, true);
+	if (!base)
+		return -ENOMEM;
+	if (attr->sfunc) {
+		ret = pmbus_add_limit_attrs(client, data, info, name,
+					    index, page, base, attr);
+		if (ret < 0)
+			return ret;
+		/*
+		 * Add generic alarm attribute only if there are no individual
+		 * alarm attributes, if there is a global alarm bit, and if
+		 * the generic status register for this page is accessible.
+		 */
+		if (!ret && attr->gbit &&
+		    pmbus_check_byte_register(client, page,
+					      data->status_register)) {
+			ret = pmbus_add_boolean(data, name, "alarm", index,
+						NULL, NULL,
+						PB_STATUS_BASE + page,
+						attr->gbit);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
+static int pmbus_add_sensor_attrs(struct i2c_client *client,
+				  struct pmbus_data *data,
+				  const char *name,
+				  const struct pmbus_sensor_attr *attrs,
+				  int nattrs)
+{
+	const struct pmbus_driver_info *info = data->info;
+	int index, i;
+	int ret;
+
+	index = 1;
+	for (i = 0; i < nattrs; i++) {
+		int page, pages;
+
+		pages = attrs->paged ? info->pages : 1;
+		for (page = 0; page < pages; page++) {
+			if (!(info->func[page] & attrs->func))
+				continue;
+			ret = pmbus_add_sensor_attrs_one(client, data, info,
+							 name, index, page,
+							 attrs);
+			if (ret)
+				return ret;
+			index++;
+		}
+		attrs++;
+	}
+	return 0;
+}
+
+static const struct pmbus_limit_attr vin_limit_attrs[] = {
+	{
+		.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,
+	}, {
+		.reg = PMBUS_VIRT_READ_VIN_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_VIN_MIN,
+		.update = true,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_VIN_MAX,
+		.update = true,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+		.attr = "reset_history",
+	},
+};
+
+static const struct pmbus_limit_attr vmon_limit_attrs[] = {
+	{
+		.reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_VOLTAGE_UV_WARNING,
+	}, {
+		.reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_VOLTAGE_UV_FAULT,
+	}, {
+		.reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_VOLTAGE_OV_WARNING,
+	}, {
+		.reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_VOLTAGE_OV_FAULT,
+	}
+};
+
+static const struct pmbus_limit_attr vout_limit_attrs[] = {
+	{
+		.reg = PMBUS_VOUT_UV_WARN_LIMIT,
+		.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,
+	}, {
+		.reg = PMBUS_VIRT_READ_VOUT_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_VOUT_MIN,
+		.update = true,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_VOUT_MAX,
+		.update = true,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+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_VIRT_READ_VMON,
+		.class = PSC_VOLTAGE_IN,
+		.label = "vmon",
+		.func = PMBUS_HAVE_VMON,
+		.sfunc = PMBUS_HAVE_STATUS_VMON,
+		.sbase = PB_STATUS_VMON_BASE,
+		.limit = vmon_limit_attrs,
+		.nlimit = ARRAY_SIZE(vmon_limit_attrs),
+	}, {
+		.reg = PMBUS_READ_VCAP,
+		.class = PSC_VOLTAGE_IN,
+		.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,
+	}, {
+		.reg = PMBUS_VIRT_READ_IIN_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_IIN_MIN,
+		.update = true,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_IIN_MAX,
+		.update = true,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+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,
+	}, {
+		.reg = PMBUS_VIRT_READ_IOUT_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_IOUT_MIN,
+		.update = true,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_IOUT_MAX,
+		.update = true,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+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,
+	}, {
+		.reg = PMBUS_VIRT_READ_PIN_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_PIN_MIN,
+		.update = true,
+		.attr = "input_lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_PIN_MAX,
+		.update = true,
+		.attr = "input_highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+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,
+	}, {
+		.reg = PMBUS_VIRT_READ_POUT_AVG,
+		.update = true,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_POUT_MIN,
+		.update = true,
+		.attr = "input_lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_POUT_MAX,
+		.update = true,
+		.attr = "input_highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_POUT_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+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,
+		.low = true,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_TEMP_UT_WARNING,
+	}, {
+		.reg = PMBUS_UT_FAULT_LIMIT,
+		.low = true,
+		.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,
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP_MIN,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP_AVG,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP_MAX,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+static const struct pmbus_limit_attr temp_limit_attrs2[] = {
+	{
+		.reg = PMBUS_UT_WARN_LIMIT,
+		.low = true,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_TEMP_UT_WARNING,
+	}, {
+		.reg = PMBUS_UT_FAULT_LIMIT,
+		.low = true,
+		.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,
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP2_MIN,
+		.attr = "lowest",
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP2_AVG,
+		.attr = "average",
+	}, {
+		.reg = PMBUS_VIRT_READ_TEMP2_MAX,
+		.attr = "highest",
+	}, {
+		.reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
+		.attr = "reset_history",
+	}
+};
+
+static const struct pmbus_limit_attr temp_limit_attrs3[] = {
+	{
+		.reg = PMBUS_UT_WARN_LIMIT,
+		.low = true,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_TEMP_UT_WARNING,
+	}, {
+		.reg = PMBUS_UT_FAULT_LIMIT,
+		.low = true,
+		.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_attrs2,
+		.nlimit = ARRAY_SIZE(temp_limit_attrs2),
+	}, {
+		.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_attrs3,
+		.nlimit = ARRAY_SIZE(temp_limit_attrs3),
+	}
+};
+
+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 int pmbus_add_fan_attributes(struct i2c_client *client,
+				    struct pmbus_data *data)
+{
+	const struct pmbus_driver_info *info = data->info;
+	int index = 1;
+	int page;
+	int ret;
+
+	for (page = 0; page < info->pages; page++) {
+		int f;
+
+		for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
+			int regval;
+
+			if (!(info->func[page] & pmbus_fan_flags[f]))
+				break;
+
+			if (!pmbus_check_word_register(client, page,
+						       pmbus_fan_registers[f]))
+				break;
+
+			/*
+			 * Skip fan if not installed.
+			 * Each fan configuration register covers multiple fans,
+			 * so we have to do some magic.
+			 */
+			regval = _pmbus_read_byte_data(client, page,
+				pmbus_fan_config_registers[f]);
+			if (regval < 0 ||
+			    (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
+				continue;
+
+			if (pmbus_add_sensor(data, "fan", "input", index,
+					     page, pmbus_fan_registers[f],
+					     PSC_FAN, true, true) == NULL)
+				return -ENOMEM;
+
+			/*
+			 * Each fan status register covers multiple fans,
+			 * so we have to do some magic.
+			 */
+			if ((info->func[page] & pmbus_fan_status_flags[f]) &&
+			    pmbus_check_byte_register(client,
+					page, pmbus_fan_status_registers[f])) {
+				int base;
+
+				if (f > 1)	/* fan 3, 4 */
+					base = PB_STATUS_FAN34_BASE + page;
+				else
+					base = PB_STATUS_FAN_BASE + page;
+				ret = pmbus_add_boolean(data, "fan",
+					"alarm", index, NULL, NULL, base,
+					PB_FAN_FAN1_WARNING >> (f & 1));
+				if (ret)
+					return ret;
+				ret = pmbus_add_boolean(data, "fan",
+					"fault", index, NULL, NULL, base,
+					PB_FAN_FAN1_FAULT >> (f & 1));
+				if (ret)
+					return ret;
+			}
+			index++;
+		}
+	}
+	return 0;
+}
+
+static int pmbus_find_attributes(struct i2c_client *client,
+				 struct pmbus_data *data)
+{
+	int ret;
+
+	/* Voltage sensors */
+	ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+				     ARRAY_SIZE(voltage_attributes));
+	if (ret)
+		return ret;
+
+	/* Current sensors */
+	ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+				     ARRAY_SIZE(current_attributes));
+	if (ret)
+		return ret;
+
+	/* Power sensors */
+	ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+				     ARRAY_SIZE(power_attributes));
+	if (ret)
+		return ret;
+
+	/* Temperature sensors */
+	ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+				     ARRAY_SIZE(temp_attributes));
+	if (ret)
+		return ret;
+
+	/* Fans */
+	ret = pmbus_add_fan_attributes(client, data);
+	return ret;
+}
+
+/*
+ * Identify chip parameters.
+ * This function is called for all chips.
+ */
+static int pmbus_identify_common(struct i2c_client *client,
+				 struct pmbus_data *data, int page)
+{
+	int vout_mode = -1;
+
+	if (pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE))
+		vout_mode = _pmbus_read_byte_data(client, page,
+						  PMBUS_VOUT_MODE);
+	if (vout_mode >= 0 && vout_mode != 0xff) {
+		/*
+		 * Not all chips support the VOUT_MODE command,
+		 * so a failure to read it is not an error.
+		 */
+		switch (vout_mode >> 5) {
+		case 0:	/* linear mode      */
+			if (data->info->format[PSC_VOLTAGE_OUT] != linear)
+				return -ENODEV;
+
+			data->exponent[page] = ((s8)(vout_mode << 3)) >> 3;
+			break;
+		case 1: /* VID mode         */
+			if (data->info->format[PSC_VOLTAGE_OUT] != vid)
+				return -ENODEV;
+			break;
+		case 2:	/* direct mode      */
+			if (data->info->format[PSC_VOLTAGE_OUT] != direct)
+				return -ENODEV;
+			break;
+		default:
+			return -ENODEV;
+		}
+	}
+
+	pmbus_clear_fault_page(client, page);
+	return 0;
+}
+
+static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
+			     struct pmbus_driver_info *info)
+{
+	struct device *dev = &client->dev;
+	int page, ret;
+
+	/*
+	 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try
+	 * to use PMBUS_STATUS_WORD instead if that is the case.
+	 * Bail out if both registers are not supported.
+	 */
+	data->status_register = PMBUS_STATUS_BYTE;
+	ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
+	if (ret < 0 || ret == 0xff) {
+		data->status_register = PMBUS_STATUS_WORD;
+		ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD);
+		if (ret < 0 || ret == 0xffff) {
+			dev_err(dev, "PMBus status register not found\n");
+			return -ENODEV;
+		}
+	}
+
+	/* Enable PEC if the controller supports it */
+	ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
+	if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
+		client->flags |= I2C_CLIENT_PEC;
+
+	pmbus_clear_faults(client);
+
+	if (info->identify) {
+		ret = (*info->identify)(client, info);
+		if (ret < 0) {
+			dev_err(dev, "Chip identification failed\n");
+			return ret;
+		}
+	}
+
+	if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
+		dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages);
+		return -ENODEV;
+	}
+
+	for (page = 0; page < info->pages; page++) {
+		ret = pmbus_identify_common(client, data, page);
+		if (ret < 0) {
+			dev_err(dev, "Failed to identify chip capabilities\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_REGULATOR)
+static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct device *dev = rdev_get_dev(rdev);
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	u8 page = rdev_get_id(rdev);
+	int ret;
+
+	ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+	if (ret < 0)
+		return ret;
+
+	return !!(ret & PB_OPERATION_CONTROL_ON);
+}
+
+static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
+{
+	struct device *dev = rdev_get_dev(rdev);
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	u8 page = rdev_get_id(rdev);
+
+	return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+				      PB_OPERATION_CONTROL_ON,
+				      enable ? PB_OPERATION_CONTROL_ON : 0);
+}
+
+static int pmbus_regulator_enable(struct regulator_dev *rdev)
+{
+	return _pmbus_regulator_on_off(rdev, 1);
+}
+
+static int pmbus_regulator_disable(struct regulator_dev *rdev)
+{
+	return _pmbus_regulator_on_off(rdev, 0);
+}
+
+const struct regulator_ops pmbus_regulator_ops = {
+	.enable = pmbus_regulator_enable,
+	.disable = pmbus_regulator_disable,
+	.is_enabled = pmbus_regulator_is_enabled,
+};
+EXPORT_SYMBOL_GPL(pmbus_regulator_ops);
+
+static int pmbus_regulator_register(struct pmbus_data *data)
+{
+	struct device *dev = data->dev;
+	const struct pmbus_driver_info *info = data->info;
+	const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
+	struct regulator_dev *rdev;
+	int i;
+
+	for (i = 0; i < info->num_regulators; i++) {
+		struct regulator_config config = { };
+
+		config.dev = dev;
+		config.driver_data = data;
+
+		if (pdata && pdata->reg_init_data)
+			config.init_data = &pdata->reg_init_data[i];
+
+		rdev = devm_regulator_register(dev, &info->reg_desc[i],
+					       &config);
+		if (IS_ERR(rdev)) {
+			dev_err(dev, "Failed to register %s regulator\n",
+				info->reg_desc[i].name);
+			return PTR_ERR(rdev);
+		}
+	}
+
+	return 0;
+}
+#else
+static int pmbus_regulator_register(struct pmbus_data *data)
+{
+	return 0;
+}
+#endif
+
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+		   struct pmbus_driver_info *info)
+{
+	struct device *dev = &client->dev;
+	const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
+	struct pmbus_data *data;
+	int ret;
+
+	if (!info)
+		return -ENODEV;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+				     | I2C_FUNC_SMBUS_BYTE_DATA
+				     | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+	data->dev = dev;
+
+	if (pdata)
+		data->flags = pdata->flags;
+	data->info = info;
+
+	ret = pmbus_init_common(client, data, info);
+	if (ret < 0)
+		return ret;
+
+	ret = pmbus_find_attributes(client, data);
+	if (ret)
+		goto out_kfree;
+
+	/*
+	 * If there are no attributes, something is wrong.
+	 * Bail out instead of trying to register nothing.
+	 */
+	if (!data->num_attributes) {
+		dev_err(dev, "No attributes found\n");
+		ret = -ENODEV;
+		goto out_kfree;
+	}
+
+	data->groups[0] = &data->group;
+	data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+							    data, data->groups);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		dev_err(dev, "Failed to register hwmon device\n");
+		goto out_kfree;
+	}
+
+	ret = pmbus_regulator_register(data);
+	if (ret)
+		goto out_unregister;
+
+	return 0;
+
+out_unregister:
+	hwmon_device_unregister(data->hwmon_dev);
+out_kfree:
+	kfree(data->group.attrs);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_probe);
+
+int pmbus_do_remove(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	hwmon_device_unregister(data->hwmon_dev);
+	kfree(data->group.attrs);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_remove);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c
new file mode 100644
index 0000000..3280382
--- /dev/null
+++ b/drivers/hwmon/pmbus/tps40422.c
@@ -0,0 +1,64 @@
+/*
+ * Hardware monitoring driver for TI TPS40422
+ *
+ * Copyright (c) 2014 Nokia Solutions and Networks.
+ *
+ * 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/i2c.h>
+#include "pmbus.h"
+
+static struct pmbus_driver_info tps40422_info = {
+	.pages = 2,
+	.format[PSC_VOLTAGE_IN] = linear,
+	.format[PSC_VOLTAGE_OUT] = linear,
+	.format[PSC_TEMPERATURE] = linear,
+	.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP2
+		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP
+		| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+	.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP2
+		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP
+		| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+};
+
+static int tps40422_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	return pmbus_do_probe(client, id, &tps40422_info);
+}
+
+static const struct i2c_device_id tps40422_id[] = {
+	{"tps40422", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tps40422_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver tps40422_driver = {
+	.driver = {
+		   .name = "tps40422",
+		   },
+	.probe = tps40422_probe,
+	.remove = pmbus_do_remove,
+	.id_table = tps40422_id,
+};
+
+module_i2c_driver(tps40422_driver);
+
+MODULE_AUTHOR("Zhu Laiwen <richard.zhu@nsn.com>");
+MODULE_DESCRIPTION("PMBus driver for TI TPS40422");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
new file mode 100644
index 0000000..fbb1479
--- /dev/null
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -0,0 +1,246 @@
+/*
+ * 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 > 0)
+			return -ENXIO;
+
+		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 > 0)
+			return -ENXIO;
+
+		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);
+
+	for (mid = ucd9000_id; mid->name[0]; mid++) {
+		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+			break;
+	}
+	if (!mid->name[0]) {
+		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 = devm_kzalloc(&client->dev, 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");
+		return ret;
+	}
+	info->pages = ret;
+	if (!info->pages) {
+		dev_err(&client->dev, "No pages configured\n");
+		return -ENODEV;
+	}
+
+	/* 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");
+		return -ENODEV;
+	}
+	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)
+				return ret;
+		}
+		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;
+	}
+
+	return pmbus_do_probe(client, mid, info);
+}
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9000_driver = {
+	.driver = {
+		.name = "ucd9000",
+	},
+	.probe = ucd9000_probe,
+	.remove = pmbus_do_remove,
+	.id_table = ucd9000_id,
+};
+
+module_i2c_driver(ucd9000_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
new file mode 100644
index 0000000..033d6ac
--- /dev/null
+++ b/drivers/hwmon/pmbus/ucd9200.c
@@ -0,0 +1,180 @@
+/*
+ * 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);
+
+	for (mid = ucd9200_id; mid->name[0]; mid++) {
+		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+			break;
+	}
+	if (!mid->name[0]) {
+		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 = devm_kzalloc(&client->dev, 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");
+		return ret;
+	}
+
+	/*
+	 * 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");
+		return -ENODEV;
+	}
+	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");
+			return ret;
+		}
+	}
+	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;
+
+	return pmbus_do_probe(client, mid, info);
+}
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9200_driver = {
+	.driver = {
+		.name = "ucd9200",
+	},
+	.probe = ucd9200_probe,
+	.remove = pmbus_do_remove,
+	.id_table = ucd9200_id,
+};
+
+module_i2c_driver(ucd9200_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
new file mode 100644
index 0000000..771802d
--- /dev/null
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -0,0 +1,420 @@
+/*
+ * Hardware monitoring driver for ZL6100 and compatibles
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/bitops.h>
+#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/ktime.h>
+#include <linux/delay.h>
+#include "pmbus.h"
+
+enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
+	     zl9101, zl9117 };
+
+struct zl6100_data {
+	int id;
+	ktime_t access;		/* chip access time */
+	int delay;		/* Delay between chip accesses in uS */
+	struct pmbus_driver_info info;
+};
+
+#define to_zl6100_data(x)  container_of(x, struct zl6100_data, info)
+
+#define ZL6100_MFR_CONFIG		0xd0
+#define ZL6100_DEVICE_ID		0xe4
+
+#define ZL6100_MFR_XTEMP_ENABLE		BIT(7)
+
+#define MFR_VMON_OV_FAULT_LIMIT		0xf5
+#define MFR_VMON_UV_FAULT_LIMIT		0xf6
+#define MFR_READ_VMON			0xf7
+
+#define VMON_UV_WARNING			BIT(5)
+#define VMON_OV_WARNING			BIT(4)
+#define VMON_UV_FAULT			BIT(1)
+#define VMON_OV_FAULT			BIT(0)
+
+#define ZL6100_WAIT_TIME		1000	/* uS	*/
+
+static ushort delay = ZL6100_WAIT_TIME;
+module_param(delay, ushort, 0644);
+MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
+
+/* Convert linear sensor value to milli-units */
+static long zl6100_l2d(s16 l)
+{
+	s16 exponent;
+	s32 mantissa;
+	long val;
+
+	exponent = l >> 11;
+	mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
+
+	val = mantissa;
+
+	/* scale result to milli-units */
+	val = val * 1000L;
+
+	if (exponent >= 0)
+		val <<= exponent;
+	else
+		val >>= -exponent;
+
+	return val;
+}
+
+#define MAX_MANTISSA	(1023 * 1000)
+#define MIN_MANTISSA	(511 * 1000)
+
+static u16 zl6100_d2l(long val)
+{
+	s16 exponent = 0, mantissa;
+	bool negative = false;
+
+	/* simple case */
+	if (val == 0)
+		return 0;
+
+	if (val < 0) {
+		negative = true;
+		val = -val;
+	}
+
+	/* Reduce large mantissa until it fits into 10 bit */
+	while (val >= MAX_MANTISSA && exponent < 15) {
+		exponent++;
+		val >>= 1;
+	}
+	/* Increase small mantissa to improve precision */
+	while (val < MIN_MANTISSA && exponent > -15) {
+		exponent--;
+		val <<= 1;
+	}
+
+	/* Convert mantissa from milli-units to units */
+	mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+	/* Ensure that resulting number is within range */
+	if (mantissa > 0x3ff)
+		mantissa = 0x3ff;
+
+	/* restore sign */
+	if (negative)
+		mantissa = -mantissa;
+
+	/* Convert to 5 bit exponent, 11 bit mantissa */
+	return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
+/* Some chips need a delay between accesses */
+static inline void zl6100_wait(const struct zl6100_data *data)
+{
+	if (data->delay) {
+		s64 delta = ktime_us_delta(ktime_get(), data->access);
+		if (delta < data->delay)
+			udelay(data->delay - delta);
+	}
+}
+
+static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct zl6100_data *data = to_zl6100_data(info);
+	int ret, vreg;
+
+	if (page > 0)
+		return -ENXIO;
+
+	if (data->id == zl2005) {
+		/*
+		 * Limit register detection is not reliable on ZL2005.
+		 * Make sure registers are not erroneously detected.
+		 */
+		switch (reg) {
+		case PMBUS_VOUT_OV_WARN_LIMIT:
+		case PMBUS_VOUT_UV_WARN_LIMIT:
+		case PMBUS_IOUT_OC_WARN_LIMIT:
+			return -ENXIO;
+		}
+	}
+
+	switch (reg) {
+	case PMBUS_VIRT_READ_VMON:
+		vreg = MFR_READ_VMON;
+		break;
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+	case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+	case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		break;
+	default:
+		if (reg >= PMBUS_VIRT_BASE)
+			return -ENXIO;
+		vreg = reg;
+		break;
+	}
+
+	zl6100_wait(data);
+	ret = pmbus_read_word_data(client, page, vreg);
+	data->access = ktime_get();
+	if (ret < 0)
+		return ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
+		break;
+	}
+
+	return ret;
+}
+
+static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct zl6100_data *data = to_zl6100_data(info);
+	int ret, status;
+
+	if (page > 0)
+		return -ENXIO;
+
+	zl6100_wait(data);
+
+	switch (reg) {
+	case PMBUS_VIRT_STATUS_VMON:
+		ret = pmbus_read_byte_data(client, 0,
+					   PMBUS_STATUS_MFR_SPECIFIC);
+		if (ret < 0)
+			break;
+
+		status = 0;
+		if (ret & VMON_UV_WARNING)
+			status |= PB_VOLTAGE_UV_WARNING;
+		if (ret & VMON_OV_WARNING)
+			status |= PB_VOLTAGE_OV_WARNING;
+		if (ret & VMON_UV_FAULT)
+			status |= PB_VOLTAGE_UV_FAULT;
+		if (ret & VMON_OV_FAULT)
+			status |= PB_VOLTAGE_OV_FAULT;
+		ret = status;
+		break;
+	default:
+		ret = pmbus_read_byte_data(client, page, reg);
+		break;
+	}
+	data->access = ktime_get();
+
+	return ret;
+}
+
+static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
+				  u16 word)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct zl6100_data *data = to_zl6100_data(info);
+	int ret, vreg;
+
+	if (page > 0)
+		return -ENXIO;
+
+	switch (reg) {
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	default:
+		if (reg >= PMBUS_VIRT_BASE)
+			return -ENXIO;
+		vreg = reg;
+	}
+
+	zl6100_wait(data);
+	ret = pmbus_write_word_data(client, page, vreg, word);
+	data->access = ktime_get();
+
+	return ret;
+}
+
+static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct zl6100_data *data = to_zl6100_data(info);
+	int ret;
+
+	if (page > 0)
+		return -ENXIO;
+
+	zl6100_wait(data);
+	ret = pmbus_write_byte(client, page, value);
+	data->access = ktime_get();
+
+	return ret;
+}
+
+static const struct i2c_device_id zl6100_id[] = {
+	{"bmr450", zl2005},
+	{"bmr451", zl2005},
+	{"bmr462", zl2008},
+	{"bmr463", zl2008},
+	{"bmr464", zl2008},
+	{"zl2004", zl2004},
+	{"zl2005", zl2005},
+	{"zl2006", zl2006},
+	{"zl2008", zl2008},
+	{"zl2105", zl2105},
+	{"zl2106", zl2106},
+	{"zl6100", zl6100},
+	{"zl6105", zl6105},
+	{"zl9101", zl9101},
+	{"zl9117", zl9117},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, zl6100_id);
+
+static int zl6100_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct zl6100_data *data;
+	struct pmbus_driver_info *info;
+	u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+	const struct i2c_device_id *mid;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA
+				     | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+		return -ENODEV;
+
+	ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
+					device_id);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read device ID\n");
+		return ret;
+	}
+	device_id[ret] = '\0';
+	dev_info(&client->dev, "Device ID %s\n", device_id);
+
+	mid = NULL;
+	for (mid = zl6100_id; mid->name[0]; mid++) {
+		if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+			break;
+	}
+	if (!mid->name[0]) {
+		dev_err(&client->dev, "Unsupported device\n");
+		return -ENODEV;
+	}
+	if (id->driver_data != mid->driver_data)
+		dev_notice(&client->dev,
+			   "Device mismatch: Configured %s, detected %s\n",
+			   id->name, mid->name);
+
+	data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->id = mid->driver_data;
+
+	/*
+	 * According to information from the chip vendor, all currently
+	 * supported chips are known to require a wait time between I2C
+	 * accesses.
+	 */
+	data->delay = delay;
+
+	/*
+	 * Since there was a direct I2C device access above, wait before
+	 * accessing the chip again.
+	 */
+	data->access = ktime_get();
+	zl6100_wait(data);
+
+	info = &data->info;
+
+	info->pages = 1;
+	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+	  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+	  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+	  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+
+	/*
+	 * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
+	 * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+	 */
+	if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+		info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
+
+	ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
+	if (ret < 0)
+		return ret;
+
+	if (ret & ZL6100_MFR_XTEMP_ENABLE)
+		info->func[0] |= PMBUS_HAVE_TEMP2;
+
+	data->access = ktime_get();
+	zl6100_wait(data);
+
+	info->read_word_data = zl6100_read_word_data;
+	info->read_byte_data = zl6100_read_byte_data;
+	info->write_word_data = zl6100_write_word_data;
+	info->write_byte = zl6100_write_byte;
+
+	return pmbus_do_probe(client, mid, info);
+}
+
+static struct i2c_driver zl6100_driver = {
+	.driver = {
+		   .name = "zl6100",
+		   },
+	.probe = zl6100_probe,
+	.remove = pmbus_do_remove,
+	.id_table = zl6100_id,
+};
+
+module_i2c_driver(zl6100_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c
new file mode 100644
index 0000000..3014e4a
--- /dev/null
+++ b/drivers/hwmon/powr1220.c
@@ -0,0 +1,391 @@
+/*
+ * powr1220.c - Driver for the Lattice POWR1220 programmable power supply
+ * and monitor. Users can read all ADC inputs along with their labels
+ * using the sysfs nodes.
+ *
+ * Copyright (c) 2014 Echo360 http://www.echo360.com
+ * Scott Kanowitz <skanowitz@echo360.com> <scott.kanowitz@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define ADC_STEP_MV			2
+#define ADC_MAX_LOW_MEASUREMENT_MV	2000
+
+enum powr1220_regs {
+	VMON_STATUS0,
+	VMON_STATUS1,
+	VMON_STATUS2,
+	OUTPUT_STATUS0,
+	OUTPUT_STATUS1,
+	OUTPUT_STATUS2,
+	INPUT_STATUS,
+	ADC_VALUE_LOW,
+	ADC_VALUE_HIGH,
+	ADC_MUX,
+	UES_BYTE0,
+	UES_BYTE1,
+	UES_BYTE2,
+	UES_BYTE3,
+	GP_OUTPUT1,
+	GP_OUTPUT2,
+	GP_OUTPUT3,
+	INPUT_VALUE,
+	RESET,
+	TRIM1_TRIM,
+	TRIM2_TRIM,
+	TRIM3_TRIM,
+	TRIM4_TRIM,
+	TRIM5_TRIM,
+	TRIM6_TRIM,
+	TRIM7_TRIM,
+	TRIM8_TRIM,
+	MAX_POWR1220_REGS
+};
+
+enum powr1220_adc_values {
+	VMON1,
+	VMON2,
+	VMON3,
+	VMON4,
+	VMON5,
+	VMON6,
+	VMON7,
+	VMON8,
+	VMON9,
+	VMON10,
+	VMON11,
+	VMON12,
+	VCCA,
+	VCCINP,
+	MAX_POWR1220_ADC_VALUES
+};
+
+struct powr1220_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	bool adc_valid[MAX_POWR1220_ADC_VALUES];
+	 /* the next value is in jiffies */
+	unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES];
+
+	/* values */
+	int adc_maxes[MAX_POWR1220_ADC_VALUES];
+	int adc_values[MAX_POWR1220_ADC_VALUES];
+};
+
+static const char * const input_names[] = {
+	[VMON1]    = "vmon1",
+	[VMON2]    = "vmon2",
+	[VMON3]    = "vmon3",
+	[VMON4]    = "vmon4",
+	[VMON5]    = "vmon5",
+	[VMON6]    = "vmon6",
+	[VMON7]    = "vmon7",
+	[VMON8]    = "vmon8",
+	[VMON9]    = "vmon9",
+	[VMON10]   = "vmon10",
+	[VMON11]   = "vmon11",
+	[VMON12]   = "vmon12",
+	[VCCA]     = "vcca",
+	[VCCINP]   = "vccinp",
+};
+
+/* Reads the specified ADC channel */
+static int powr1220_read_adc(struct device *dev, int ch_num)
+{
+	struct powr1220_data *data = dev_get_drvdata(dev);
+	int reading;
+	int result;
+	int adc_range = 0;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) ||
+			!data->adc_valid[ch_num]) {
+		/*
+		 * figure out if we need to use the attenuator for
+		 * high inputs or inputs that we don't yet have a measurement
+		 * for. We dynamically set the attenuator depending on the
+		 * max reading.
+		 */
+		if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV ||
+				data->adc_maxes[ch_num] == 0)
+			adc_range = 1 << 4;
+
+		/* set the attenuator and mux */
+		result = i2c_smbus_write_byte_data(data->client, ADC_MUX,
+				adc_range | ch_num);
+		if (result)
+			goto exit;
+
+		/*
+		 * wait at least Tconvert time (200 us) for the
+		 * conversion to complete
+		 */
+		udelay(200);
+
+		/* get the ADC reading */
+		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW);
+		if (result < 0)
+			goto exit;
+
+		reading = result >> 4;
+
+		/* get the upper half of the reading */
+		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH);
+		if (result < 0)
+			goto exit;
+
+		reading |= result << 4;
+
+		/* now convert the reading to a voltage */
+		reading *= ADC_STEP_MV;
+		data->adc_values[ch_num] = reading;
+		data->adc_valid[ch_num] = true;
+		data->adc_last_updated[ch_num] = jiffies;
+		result = reading;
+
+		if (reading > data->adc_maxes[ch_num])
+			data->adc_maxes[ch_num] = reading;
+	} else {
+		result = data->adc_values[ch_num];
+	}
+
+exit:
+	mutex_unlock(&data->update_lock);
+
+	return result;
+}
+
+/* Shows the voltage associated with the specified ADC channel */
+static ssize_t powr1220_show_voltage(struct device *dev,
+	struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	int adc_val = powr1220_read_adc(dev, attr->index);
+
+	if (adc_val < 0)
+		return adc_val;
+
+	return sprintf(buf, "%d\n", adc_val);
+}
+
+/* Shows the maximum setting associated with the specified ADC channel */
+static ssize_t powr1220_show_max(struct device *dev,
+	struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+	struct powr1220_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", data->adc_maxes[attr->index]);
+}
+
+/* Shows the label associated with the specified ADC channel */
+static ssize_t powr1220_show_label(struct device *dev,
+	struct device_attribute *dev_attr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+	return sprintf(buf, "%s\n", input_names[attr->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON1);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON2);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON3);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON4);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON5);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON6);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON7);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON8);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON9);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON10);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON11);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VMON12);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VCCA);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, powr1220_show_voltage, NULL,
+	VCCINP);
+
+static SENSOR_DEVICE_ATTR(in0_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON1);
+static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON2);
+static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON3);
+static SENSOR_DEVICE_ATTR(in3_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON4);
+static SENSOR_DEVICE_ATTR(in4_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON5);
+static SENSOR_DEVICE_ATTR(in5_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON6);
+static SENSOR_DEVICE_ATTR(in6_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON7);
+static SENSOR_DEVICE_ATTR(in7_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON8);
+static SENSOR_DEVICE_ATTR(in8_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON9);
+static SENSOR_DEVICE_ATTR(in9_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON10);
+static SENSOR_DEVICE_ATTR(in10_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON11);
+static SENSOR_DEVICE_ATTR(in11_highest, S_IRUGO, powr1220_show_max, NULL,
+	VMON12);
+static SENSOR_DEVICE_ATTR(in12_highest, S_IRUGO, powr1220_show_max, NULL,
+	VCCA);
+static SENSOR_DEVICE_ATTR(in13_highest, S_IRUGO, powr1220_show_max, NULL,
+	VCCINP);
+
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON1);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON2);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON3);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON4);
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON5);
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON6);
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON7);
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON8);
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON9);
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON10);
+static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON11);
+static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, powr1220_show_label, NULL,
+	VMON12);
+static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, powr1220_show_label, NULL,
+	VCCA);
+static SENSOR_DEVICE_ATTR(in13_label, S_IRUGO, powr1220_show_label, NULL,
+	VCCINP);
+
+static struct attribute *powr1220_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+
+	&sensor_dev_attr_in0_highest.dev_attr.attr,
+	&sensor_dev_attr_in1_highest.dev_attr.attr,
+	&sensor_dev_attr_in2_highest.dev_attr.attr,
+	&sensor_dev_attr_in3_highest.dev_attr.attr,
+	&sensor_dev_attr_in4_highest.dev_attr.attr,
+	&sensor_dev_attr_in5_highest.dev_attr.attr,
+	&sensor_dev_attr_in6_highest.dev_attr.attr,
+	&sensor_dev_attr_in7_highest.dev_attr.attr,
+	&sensor_dev_attr_in8_highest.dev_attr.attr,
+	&sensor_dev_attr_in9_highest.dev_attr.attr,
+	&sensor_dev_attr_in10_highest.dev_attr.attr,
+	&sensor_dev_attr_in11_highest.dev_attr.attr,
+	&sensor_dev_attr_in12_highest.dev_attr.attr,
+	&sensor_dev_attr_in13_highest.dev_attr.attr,
+
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	&sensor_dev_attr_in5_label.dev_attr.attr,
+	&sensor_dev_attr_in6_label.dev_attr.attr,
+	&sensor_dev_attr_in7_label.dev_attr.attr,
+	&sensor_dev_attr_in8_label.dev_attr.attr,
+	&sensor_dev_attr_in9_label.dev_attr.attr,
+	&sensor_dev_attr_in10_label.dev_attr.attr,
+	&sensor_dev_attr_in11_label.dev_attr.attr,
+	&sensor_dev_attr_in12_label.dev_attr.attr,
+	&sensor_dev_attr_in13_label.dev_attr.attr,
+
+	NULL
+};
+
+ATTRIBUTE_GROUPS(powr1220);
+
+static int powr1220_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct powr1220_data *data;
+	struct device *hwmon_dev;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->update_lock);
+	data->client = client;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+			client->name, data, powr1220_groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id powr1220_ids[] = {
+	{ "powr1220", 0, },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, powr1220_ids);
+
+static struct i2c_driver powr1220_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "powr1220",
+	},
+	.probe		= powr1220_probe,
+	.id_table	= powr1220_ids,
+};
+
+module_i2c_driver(powr1220_driver);
+
+MODULE_AUTHOR("Scott Kanowitz");
+MODULE_DESCRIPTION("POWR1220 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
new file mode 100644
index 0000000..3e23003
--- /dev/null
+++ b/drivers/hwmon/pwm-fan.c
@@ -0,0 +1,343 @@
+/*
+ * pwm-fan.c - Hwmon driver for fans connected to PWM lines.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * 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/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+
+#define MAX_PWM 255
+
+struct pwm_fan_ctx {
+	struct mutex lock;
+	struct pwm_device *pwm;
+	unsigned int pwm_value;
+	unsigned int pwm_fan_state;
+	unsigned int pwm_fan_max_state;
+	unsigned int *pwm_fan_cooling_levels;
+	struct thermal_cooling_device *cdev;
+};
+
+static int  __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
+{
+	unsigned long duty;
+	int ret = 0;
+
+	mutex_lock(&ctx->lock);
+	if (ctx->pwm_value == pwm)
+		goto exit_set_pwm_err;
+
+	duty = DIV_ROUND_UP(pwm * (ctx->pwm->period - 1), MAX_PWM);
+	ret = pwm_config(ctx->pwm, duty, ctx->pwm->period);
+	if (ret)
+		goto exit_set_pwm_err;
+
+	if (pwm == 0)
+		pwm_disable(ctx->pwm);
+
+	if (ctx->pwm_value == 0) {
+		ret = pwm_enable(ctx->pwm);
+		if (ret)
+			goto exit_set_pwm_err;
+	}
+
+	ctx->pwm_value = pwm;
+exit_set_pwm_err:
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm)
+{
+	int i;
+
+	for (i = 0; i < ctx->pwm_fan_max_state; ++i)
+		if (pwm < ctx->pwm_fan_cooling_levels[i + 1])
+			break;
+
+	ctx->pwm_fan_state = i;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	unsigned long pwm;
+	int ret;
+
+	if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM)
+		return -EINVAL;
+
+	ret = __set_pwm(ctx, pwm);
+	if (ret)
+		return ret;
+
+	pwm_fan_update_state(ctx, pwm);
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ctx->pwm_value);
+}
+
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+
+static struct attribute *pwm_fan_attrs[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(pwm_fan);
+
+/* thermal cooling device callbacks */
+static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	struct pwm_fan_ctx *ctx = cdev->devdata;
+
+	if (!ctx)
+		return -EINVAL;
+
+	*state = ctx->pwm_fan_max_state;
+
+	return 0;
+}
+
+static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	struct pwm_fan_ctx *ctx = cdev->devdata;
+
+	if (!ctx)
+		return -EINVAL;
+
+	*state = ctx->pwm_fan_state;
+
+	return 0;
+}
+
+static int
+pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
+{
+	struct pwm_fan_ctx *ctx = cdev->devdata;
+	int ret;
+
+	if (!ctx || (state > ctx->pwm_fan_max_state))
+		return -EINVAL;
+
+	if (state == ctx->pwm_fan_state)
+		return 0;
+
+	ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
+	if (ret) {
+		dev_err(&cdev->device, "Cannot set pwm!\n");
+		return ret;
+	}
+
+	ctx->pwm_fan_state = state;
+
+	return ret;
+}
+
+static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {
+	.get_max_state = pwm_fan_get_max_state,
+	.get_cur_state = pwm_fan_get_cur_state,
+	.set_cur_state = pwm_fan_set_cur_state,
+};
+
+static int pwm_fan_of_get_cooling_data(struct device *dev,
+				       struct pwm_fan_ctx *ctx)
+{
+	struct device_node *np = dev->of_node;
+	int num, i, ret;
+
+	if (!of_find_property(np, "cooling-levels", NULL))
+		return 0;
+
+	ret = of_property_count_u32_elems(np, "cooling-levels");
+	if (ret <= 0) {
+		dev_err(dev, "Wrong data!\n");
+		return ret ? : -EINVAL;
+	}
+
+	num = ret;
+	ctx->pwm_fan_cooling_levels = devm_kzalloc(dev, num * sizeof(u32),
+						   GFP_KERNEL);
+	if (!ctx->pwm_fan_cooling_levels)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "cooling-levels",
+					 ctx->pwm_fan_cooling_levels, num);
+	if (ret) {
+		dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
+		return ret;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (ctx->pwm_fan_cooling_levels[i] > MAX_PWM) {
+			dev_err(dev, "PWM fan state[%d]:%d > %d\n", i,
+				ctx->pwm_fan_cooling_levels[i], MAX_PWM);
+			return -EINVAL;
+		}
+	}
+
+	ctx->pwm_fan_max_state = num - 1;
+
+	return 0;
+}
+
+static int pwm_fan_probe(struct platform_device *pdev)
+{
+	struct thermal_cooling_device *cdev;
+	struct pwm_fan_ctx *ctx;
+	struct device *hwmon;
+	int duty_cycle;
+	int ret;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mutex_init(&ctx->lock);
+
+	ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
+	if (IS_ERR(ctx->pwm)) {
+		dev_err(&pdev->dev, "Could not get PWM\n");
+		return PTR_ERR(ctx->pwm);
+	}
+
+	platform_set_drvdata(pdev, ctx);
+
+	/* Set duty cycle to maximum allowed */
+	duty_cycle = ctx->pwm->period - 1;
+	ctx->pwm_value = MAX_PWM;
+
+	ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->period);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to configure PWM\n");
+		return ret;
+	}
+
+	/* Enbale PWM output */
+	ret = pwm_enable(ctx->pwm);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to enable PWM\n");
+		return ret;
+	}
+
+	hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan",
+						       ctx, pwm_fan_groups);
+	if (IS_ERR(hwmon)) {
+		dev_err(&pdev->dev, "Failed to register hwmon device\n");
+		pwm_disable(ctx->pwm);
+		return PTR_ERR(hwmon);
+	}
+
+	ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
+	if (ret)
+		return ret;
+
+	ctx->pwm_fan_state = ctx->pwm_fan_max_state;
+	if (IS_ENABLED(CONFIG_THERMAL)) {
+		cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
+							  "pwm-fan", ctx,
+							  &pwm_fan_cooling_ops);
+		if (IS_ERR(cdev)) {
+			dev_err(&pdev->dev,
+				"Failed to register pwm-fan as cooling device");
+			pwm_disable(ctx->pwm);
+			return PTR_ERR(cdev);
+		}
+		ctx->cdev = cdev;
+		thermal_cdev_update(cdev);
+	}
+
+	return 0;
+}
+
+static int pwm_fan_remove(struct platform_device *pdev)
+{
+	struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
+
+	thermal_cooling_device_unregister(ctx->cdev);
+	if (ctx->pwm_value)
+		pwm_disable(ctx->pwm);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pwm_fan_suspend(struct device *dev)
+{
+	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	if (ctx->pwm_value)
+		pwm_disable(ctx->pwm);
+	return 0;
+}
+
+static int pwm_fan_resume(struct device *dev)
+{
+	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	unsigned long duty;
+	int ret;
+
+	if (ctx->pwm_value == 0)
+		return 0;
+
+	duty = DIV_ROUND_UP(ctx->pwm_value * (ctx->pwm->period - 1), MAX_PWM);
+	ret = pwm_config(ctx->pwm, duty, ctx->pwm->period);
+	if (ret)
+		return ret;
+	return pwm_enable(ctx->pwm);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume);
+
+static const struct of_device_id of_pwm_fan_match[] = {
+	{ .compatible = "pwm-fan", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
+
+static struct platform_driver pwm_fan_driver = {
+	.probe		= pwm_fan_probe,
+	.remove		= pwm_fan_remove,
+	.driver	= {
+		.name		= "pwm-fan",
+		.pm		= &pwm_fan_pm,
+		.of_match_table	= of_pwm_fan_match,
+	},
+};
+
+module_platform_driver(pwm_fan_driver);
+
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_ALIAS("platform:pwm-fan");
+MODULE_DESCRIPTION("PWM FAN driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
new file mode 100644
index 0000000..0c4710d
--- /dev/null
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -0,0 +1,391 @@
+/* linux/drivers/hwmon/s3c-hwmon.c
+ *
+ * Copyright (C) 2005, 2008, 2009 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX/S3C64XX ADC hwmon support
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <plat/adc.h>
+#include <linux/platform_data/hwmon-s3c.h>
+
+struct s3c_hwmon_attr {
+	struct sensor_device_attribute	in;
+	struct sensor_device_attribute	label;
+	char				in_name[12];
+	char				label_name[12];
+};
+
+/**
+ * struct s3c_hwmon - ADC hwmon client information
+ * @lock: Access lock to serialise the conversions.
+ * @client: The client we registered with the S3C ADC core.
+ * @hwmon_dev: The hwmon device we created.
+ * @attr: The holders for the channel attributes.
+*/
+struct s3c_hwmon {
+	struct mutex		lock;
+	struct s3c_adc_client	*client;
+	struct device		*hwmon_dev;
+
+	struct s3c_hwmon_attr	attrs[8];
+};
+
+/**
+ * s3c_hwmon_read_ch - read a value from a given adc channel.
+ * @dev: The device.
+ * @hwmon: Our state.
+ * @channel: The channel we're reading from.
+ *
+ * Read a value from the @channel with the proper locking and sleep until
+ * either the read completes or we timeout awaiting the ADC core to get
+ * back to us.
+ */
+static int s3c_hwmon_read_ch(struct device *dev,
+			     struct s3c_hwmon *hwmon, int channel)
+{
+	int ret;
+
+	ret = mutex_lock_interruptible(&hwmon->lock);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "reading channel %d\n", channel);
+
+	ret = s3c_adc_read(hwmon->client, channel);
+	mutex_unlock(&hwmon->lock);
+
+	return ret;
+}
+
+#ifdef CONFIG_SENSORS_S3C_RAW
+/**
+ * s3c_hwmon_show_raw - show a conversion from the raw channel number.
+ * @dev: The device that the attribute belongs to.
+ * @attr: The attribute being read.
+ * @buf: The result buffer.
+ *
+ * This show deals with the raw attribute, registered for each possible
+ * ADC channel. This does a conversion and returns the raw (un-scaled)
+ * value returned from the hardware.
+ */
+static ssize_t s3c_hwmon_show_raw(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev));
+	struct sensor_device_attribute *sa = to_sensor_dev_attr(attr);
+	int ret;
+
+	ret = s3c_hwmon_read_ch(dev, adc, sa->index);
+
+	return  (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
+static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
+static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
+static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
+static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
+static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
+static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
+static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
+
+static struct attribute *s3c_hwmon_attrs[9] = {
+	&sensor_dev_attr_adc0_raw.dev_attr.attr,
+	&sensor_dev_attr_adc1_raw.dev_attr.attr,
+	&sensor_dev_attr_adc2_raw.dev_attr.attr,
+	&sensor_dev_attr_adc3_raw.dev_attr.attr,
+	&sensor_dev_attr_adc4_raw.dev_attr.attr,
+	&sensor_dev_attr_adc5_raw.dev_attr.attr,
+	&sensor_dev_attr_adc6_raw.dev_attr.attr,
+	&sensor_dev_attr_adc7_raw.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group s3c_hwmon_attrgroup = {
+	.attrs	= s3c_hwmon_attrs,
+};
+
+static inline int s3c_hwmon_add_raw(struct device *dev)
+{
+	return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup);
+}
+
+static inline void s3c_hwmon_remove_raw(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup);
+}
+
+#else
+
+static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; }
+static inline void s3c_hwmon_remove_raw(struct device *dev) { }
+
+#endif /* CONFIG_SENSORS_S3C_RAW */
+
+/**
+ * s3c_hwmon_ch_show - show value of a given channel
+ * @dev: The device that the attribute belongs to.
+ * @attr: The attribute being read.
+ * @buf: The result buffer.
+ *
+ * Read a value from the ADC and scale it before returning it to the
+ * caller. The scale factor is gained from the channel configuration
+ * passed via the platform data when the device was registered.
+ */
+static ssize_t s3c_hwmon_ch_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
+	struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
+	struct s3c_hwmon_chcfg *cfg;
+	int ret;
+
+	cfg = pdata->in[sen_attr->index];
+
+	ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index);
+	if (ret < 0)
+		return ret;
+
+	ret *= cfg->mult;
+	ret = DIV_ROUND_CLOSEST(ret, cfg->div);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+/**
+ * s3c_hwmon_label_show - show label name of the given channel.
+ * @dev: The device that the attribute belongs to.
+ * @attr: The attribute being read.
+ * @buf: The result buffer.
+ *
+ * Return the label name of a given channel
+ */
+static ssize_t s3c_hwmon_label_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
+	struct s3c_hwmon_chcfg *cfg;
+
+	cfg = pdata->in[sen_attr->index];
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name);
+}
+
+/**
+ * s3c_hwmon_create_attr - create hwmon attribute for given channel.
+ * @dev: The device to create the attribute on.
+ * @cfg: The channel configuration passed from the platform data.
+ * @channel: The ADC channel number to process.
+ *
+ * Create the scaled attribute for use with hwmon from the specified
+ * platform data in @pdata. The sysfs entry is handled by the routine
+ * s3c_hwmon_ch_show().
+ *
+ * The attribute name is taken from the configuration data if present
+ * otherwise the name is taken by concatenating in_ with the channel
+ * number.
+ */
+static int s3c_hwmon_create_attr(struct device *dev,
+				 struct s3c_hwmon_chcfg *cfg,
+				 struct s3c_hwmon_attr *attrs,
+				 int channel)
+{
+	struct sensor_device_attribute *attr;
+	int ret;
+
+	snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel);
+
+	attr = &attrs->in;
+	attr->index = channel;
+	sysfs_attr_init(&attr->dev_attr.attr);
+	attr->dev_attr.attr.name  = attrs->in_name;
+	attr->dev_attr.attr.mode  = S_IRUGO;
+	attr->dev_attr.show = s3c_hwmon_ch_show;
+
+	ret =  device_create_file(dev, &attr->dev_attr);
+	if (ret < 0) {
+		dev_err(dev, "failed to create input attribute\n");
+		return ret;
+	}
+
+	/* if this has a name, add a label */
+	if (cfg->name) {
+		snprintf(attrs->label_name, sizeof(attrs->label_name),
+			 "in%d_label", channel);
+
+		attr = &attrs->label;
+		attr->index = channel;
+		sysfs_attr_init(&attr->dev_attr.attr);
+		attr->dev_attr.attr.name  = attrs->label_name;
+		attr->dev_attr.attr.mode  = S_IRUGO;
+		attr->dev_attr.show = s3c_hwmon_label_show;
+
+		ret = device_create_file(dev, &attr->dev_attr);
+		if (ret < 0) {
+			device_remove_file(dev, &attrs->in.dev_attr);
+			dev_err(dev, "failed to create label attribute\n");
+		}
+	}
+
+	return ret;
+}
+
+static void s3c_hwmon_remove_attr(struct device *dev,
+				  struct s3c_hwmon_attr *attrs)
+{
+	device_remove_file(dev, &attrs->in.dev_attr);
+	device_remove_file(dev, &attrs->label.dev_attr);
+}
+
+/**
+ * s3c_hwmon_probe - device probe entry.
+ * @dev: The device being probed.
+*/
+static int s3c_hwmon_probe(struct platform_device *dev)
+{
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev);
+	struct s3c_hwmon *hwmon;
+	int ret = 0;
+	int i;
+
+	if (!pdata) {
+		dev_err(&dev->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+
+	hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL);
+	if (hwmon == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(dev, hwmon);
+
+	mutex_init(&hwmon->lock);
+
+	/* Register with the core ADC driver. */
+
+	hwmon->client = s3c_adc_register(dev, NULL, NULL, 0);
+	if (IS_ERR(hwmon->client)) {
+		dev_err(&dev->dev, "cannot register adc\n");
+		return PTR_ERR(hwmon->client);
+	}
+
+	/* add attributes for our adc devices. */
+
+	ret = s3c_hwmon_add_raw(&dev->dev);
+	if (ret)
+		goto err_registered;
+
+	/* register with the hwmon core */
+
+	hwmon->hwmon_dev = hwmon_device_register(&dev->dev);
+	if (IS_ERR(hwmon->hwmon_dev)) {
+		dev_err(&dev->dev, "error registering with hwmon\n");
+		ret = PTR_ERR(hwmon->hwmon_dev);
+		goto err_raw_attribute;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->in); i++) {
+		struct s3c_hwmon_chcfg *cfg = pdata->in[i];
+
+		if (!cfg)
+			continue;
+
+		if (cfg->mult >= 0x10000)
+			dev_warn(&dev->dev,
+				 "channel %d multiplier too large\n",
+				 i);
+
+		if (cfg->div == 0) {
+			dev_err(&dev->dev, "channel %d divider zero\n", i);
+			continue;
+		}
+
+		ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i],
+					    &hwmon->attrs[i], i);
+		if (ret) {
+			dev_err(&dev->dev,
+					"error creating channel %d\n", i);
+
+			for (i--; i >= 0; i--)
+				s3c_hwmon_remove_attr(&dev->dev,
+							      &hwmon->attrs[i]);
+
+			goto err_hwmon_register;
+		}
+	}
+
+	return 0;
+
+ err_hwmon_register:
+	hwmon_device_unregister(hwmon->hwmon_dev);
+
+ err_raw_attribute:
+	s3c_hwmon_remove_raw(&dev->dev);
+
+ err_registered:
+	s3c_adc_release(hwmon->client);
+
+	return ret;
+}
+
+static int s3c_hwmon_remove(struct platform_device *dev)
+{
+	struct s3c_hwmon *hwmon = platform_get_drvdata(dev);
+	int i;
+
+	s3c_hwmon_remove_raw(&dev->dev);
+
+	for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++)
+		s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]);
+
+	hwmon_device_unregister(hwmon->hwmon_dev);
+	s3c_adc_release(hwmon->client);
+
+	return 0;
+}
+
+static struct platform_driver s3c_hwmon_driver = {
+	.driver	= {
+		.name		= "s3c-hwmon",
+	},
+	.probe		= s3c_hwmon_probe,
+	.remove		= s3c_hwmon_remove,
+};
+
+module_platform_driver(s3c_hwmon_driver);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C ADC HWMon driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c-hwmon");
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
new file mode 100644
index 0000000..19f85c0
--- /dev/null
+++ b/drivers/hwmon/sch5627.c
@@ -0,0 +1,604 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, 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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include "sch56xx-common.h"
+
+#define DRVNAME "sch5627"
+#define DEVNAME DRVNAME /* We only support one model */
+
+#define SCH5627_HWMON_ID		0xa5
+#define SCH5627_COMPANY_ID		0x5c
+#define SCH5627_PRIMARY_ID		0xa0
+
+#define SCH5627_REG_BUILD_CODE		0x39
+#define SCH5627_REG_BUILD_ID		0x3a
+#define SCH5627_REG_HWMON_ID		0x3c
+#define SCH5627_REG_HWMON_REV		0x3d
+#define SCH5627_REG_COMPANY_ID		0x3e
+#define SCH5627_REG_PRIMARY_ID		0x3f
+#define SCH5627_REG_CTRL		0x40
+
+#define SCH5627_NO_TEMPS		8
+#define SCH5627_NO_FANS			4
+#define SCH5627_NO_IN			5
+
+static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
+	0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
+static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
+	0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
+static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
+	0, 0, 1, 1, 0, 0, 0, 1 };
+static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
+	0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
+static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
+	0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
+
+static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
+	0x2C, 0x2E, 0x30, 0x32 };
+static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
+	0x62, 0x64, 0x66, 0x68 };
+
+static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
+	0x22, 0x23, 0x24, 0x25, 0x189 };
+static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
+	0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
+static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
+	1, 0, 1, 0, 1 };
+static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
+	10745, 3660, 9765, 10745, 3660 };
+static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
+	"VCC", "VTT", "VBAT", "VTR", "V_IN" };
+
+struct sch5627_data {
+	unsigned short addr;
+	struct device *hwmon_dev;
+	struct sch56xx_watchdog_data *watchdog;
+	u8 control;
+	u8 temp_max[SCH5627_NO_TEMPS];
+	u8 temp_crit[SCH5627_NO_TEMPS];
+	u16 fan_min[SCH5627_NO_FANS];
+
+	struct mutex update_lock;
+	unsigned long last_battery;	/* In jiffies */
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	u16 temp[SCH5627_NO_TEMPS];
+	u16 fan[SCH5627_NO_FANS];
+	u16 in[SCH5627_NO_IN];
+};
+
+static struct sch5627_data *sch5627_update_device(struct device *dev)
+{
+	struct sch5627_data *data = dev_get_drvdata(dev);
+	struct sch5627_data *ret = data;
+	int i, val;
+
+	mutex_lock(&data->update_lock);
+
+	/* Trigger a Vbat voltage measurement every 5 minutes */
+	if (time_after(jiffies, data->last_battery + 300 * HZ)) {
+		sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
+					  data->control | 0x10);
+		data->last_battery = jiffies;
+	}
+
+	/* Cache the values for 1 second */
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		for (i = 0; i < SCH5627_NO_TEMPS; i++) {
+			val = sch56xx_read_virtual_reg12(data->addr,
+				SCH5627_REG_TEMP_MSB[i],
+				SCH5627_REG_TEMP_LSN[i],
+				SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i] = val;
+		}
+
+		for (i = 0; i < SCH5627_NO_FANS; i++) {
+			val = sch56xx_read_virtual_reg16(data->addr,
+							 SCH5627_REG_FAN[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->fan[i] = val;
+		}
+
+		for (i = 0; i < SCH5627_NO_IN; i++) {
+			val = sch56xx_read_virtual_reg12(data->addr,
+				SCH5627_REG_IN_MSB[i],
+				SCH5627_REG_IN_LSN[i],
+				SCH5627_REG_IN_HIGH_NIBBLE[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->in[i] = val;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static int sch5627_read_limits(struct sch5627_data *data)
+{
+	int i, val;
+
+	for (i = 0; i < SCH5627_NO_TEMPS; i++) {
+		/*
+		 * Note what SMSC calls ABS, is what lm_sensors calls max
+		 * (aka high), and HIGH is what lm_sensors calls crit.
+		 */
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5627_REG_TEMP_ABS[i]);
+		if (val < 0)
+			return val;
+		data->temp_max[i] = val;
+
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5627_REG_TEMP_HIGH[i]);
+		if (val < 0)
+			return val;
+		data->temp_crit[i] = val;
+	}
+	for (i = 0; i < SCH5627_NO_FANS; i++) {
+		val = sch56xx_read_virtual_reg16(data->addr,
+						 SCH5627_REG_FAN_MIN[i]);
+		if (val < 0)
+			return val;
+		data->fan_min[i] = val;
+	}
+
+	return 0;
+}
+
+static int reg_to_temp(u16 reg)
+{
+	return (reg * 625) / 10 - 64000;
+}
+
+static int reg_to_temp_limit(u8 reg)
+{
+	return (reg - 64) * 1000;
+}
+
+static int reg_to_rpm(u16 reg)
+{
+	if (reg == 0)
+		return -EIO;
+	if (reg == 0xffff)
+		return 0;
+
+	return 5400540 / reg;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
+}
+
+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 sch5627_data *data = sch5627_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = reg_to_temp(data->temp[attr->index]);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = sch5627_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = dev_get_drvdata(dev);
+	int val;
+
+	val = reg_to_temp_limit(data->temp_max[attr->index]);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = dev_get_drvdata(dev);
+	int val;
+
+	val = reg_to_temp_limit(data->temp_crit[attr->index]);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = sch5627_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = reg_to_rpm(data->fan[attr->index]);
+	if (val < 0)
+		return val;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = sch5627_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			data->fan[attr->index] == 0xffff);
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = dev_get_drvdata(dev);
+	int val = reg_to_rpm(data->fan_min[attr->index]);
+	if (val < 0)
+		return val;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5627_data *data = sch5627_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = DIV_ROUND_CLOSEST(
+		data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index],
+		10000);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_in_label(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			SCH5627_IN_LABELS[attr->index]);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_temp_fault, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_temp_fault, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IRUGO, show_temp_max, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IRUGO, show_temp_max, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_crit, S_IRUGO, show_temp_crit, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_crit, S_IRUGO, show_temp_crit, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan_min, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO, show_fan_min, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IRUGO, show_fan_min, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_in_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_in_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_in_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_in_label, NULL, 3);
+
+static struct attribute *sch5627_attributes[] = {
+	&dev_attr_name.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	&sensor_dev_attr_temp5_fault.dev_attr.attr,
+	&sensor_dev_attr_temp6_fault.dev_attr.attr,
+	&sensor_dev_attr_temp7_fault.dev_attr.attr,
+	&sensor_dev_attr_temp8_fault.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp4_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp6_max.dev_attr.attr,
+	&sensor_dev_attr_temp7_max.dev_attr.attr,
+	&sensor_dev_attr_temp8_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp4_crit.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan3_fault.dev_attr.attr,
+	&sensor_dev_attr_fan4_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	/* No in4_label as in4 is a generic input pin */
+
+	NULL
+};
+
+static const struct attribute_group sch5627_group = {
+	.attrs = sch5627_attributes,
+};
+
+static int sch5627_remove(struct platform_device *pdev)
+{
+	struct sch5627_data *data = platform_get_drvdata(pdev);
+
+	if (data->watchdog)
+		sch56xx_watchdog_unregister(data->watchdog);
+
+	if (data->hwmon_dev)
+		hwmon_device_unregister(data->hwmon_dev);
+
+	sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
+
+	return 0;
+}
+
+static int sch5627_probe(struct platform_device *pdev)
+{
+	struct sch5627_data *data;
+	int err, build_code, build_id, hwmon_rev, val;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);
+	if (val < 0) {
+		err = val;
+		goto error;
+	}
+	if (val != SCH5627_HWMON_ID) {
+		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
+		       val, SCH5627_HWMON_ID);
+		err = -ENODEV;
+		goto error;
+	}
+
+	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);
+	if (val < 0) {
+		err = val;
+		goto error;
+	}
+	if (val != SCH5627_COMPANY_ID) {
+		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
+		       val, SCH5627_COMPANY_ID);
+		err = -ENODEV;
+		goto error;
+	}
+
+	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);
+	if (val < 0) {
+		err = val;
+		goto error;
+	}
+	if (val != SCH5627_PRIMARY_ID) {
+		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
+		       val, SCH5627_PRIMARY_ID);
+		err = -ENODEV;
+		goto error;
+	}
+
+	build_code = sch56xx_read_virtual_reg(data->addr,
+					      SCH5627_REG_BUILD_CODE);
+	if (build_code < 0) {
+		err = build_code;
+		goto error;
+	}
+
+	build_id = sch56xx_read_virtual_reg16(data->addr,
+					      SCH5627_REG_BUILD_ID);
+	if (build_id < 0) {
+		err = build_id;
+		goto error;
+	}
+
+	hwmon_rev = sch56xx_read_virtual_reg(data->addr,
+					     SCH5627_REG_HWMON_REV);
+	if (hwmon_rev < 0) {
+		err = hwmon_rev;
+		goto error;
+	}
+
+	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);
+	if (val < 0) {
+		err = val;
+		goto error;
+	}
+	data->control = val;
+	if (!(data->control & 0x01)) {
+		pr_err("hardware monitoring not enabled\n");
+		err = -ENODEV;
+		goto error;
+	}
+	/* Trigger a Vbat voltage measurement, so that we get a valid reading
+	   the first time we read Vbat */
+	sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
+				  data->control | 0x10);
+	data->last_battery = jiffies;
+
+	/*
+	 * Read limits, we do this only once as reading a register on
+	 * the sch5627 is quite expensive (and they don't change).
+	 */
+	err = sch5627_read_limits(data);
+	if (err)
+		goto error;
+
+	pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
+	pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
+		build_code, build_id, hwmon_rev);
+
+	/* Register sysfs interface files */
+	err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group);
+	if (err)
+		goto error;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		data->hwmon_dev = NULL;
+		goto error;
+	}
+
+	/* Note failing to register the watchdog is not a fatal error */
+	data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
+			(build_code << 24) | (build_id << 8) | hwmon_rev,
+			&data->update_lock, 1);
+
+	return 0;
+
+error:
+	sch5627_remove(pdev);
+	return err;
+}
+
+static struct platform_driver sch5627_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= sch5627_probe,
+	.remove		= sch5627_remove,
+};
+
+module_platform_driver(sch5627_driver);
+
+MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
new file mode 100644
index 0000000..131a281
--- /dev/null
+++ b/drivers/hwmon/sch5636.c
@@ -0,0 +1,534 @@
+/***************************************************************************
+ *   Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, 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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include "sch56xx-common.h"
+
+#define DRVNAME "sch5636"
+#define DEVNAME "theseus" /* We only support one model for now */
+
+#define SCH5636_REG_FUJITSU_ID		0x780
+#define SCH5636_REG_FUJITSU_REV		0x783
+
+#define SCH5636_NO_INS			5
+#define SCH5636_NO_TEMPS		16
+#define SCH5636_NO_FANS			8
+
+static const u16 SCH5636_REG_IN_VAL[SCH5636_NO_INS] = {
+	0x22, 0x23, 0x24, 0x25, 0x189 };
+static const u16 SCH5636_REG_IN_FACTORS[SCH5636_NO_INS] = {
+	4400, 1500, 4000, 4400, 16000 };
+static const char * const SCH5636_IN_LABELS[SCH5636_NO_INS] = {
+	"3.3V", "VREF", "VBAT", "3.3AUX", "12V" };
+
+static const u16 SCH5636_REG_TEMP_VAL[SCH5636_NO_TEMPS] = {
+	0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181,
+	0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C };
+#define SCH5636_REG_TEMP_CTRL(i)	(0x790 + (i))
+#define SCH5636_TEMP_WORKING		0x01
+#define SCH5636_TEMP_ALARM		0x02
+#define SCH5636_TEMP_DEACTIVATED	0x80
+
+static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = {
+	0x2C, 0x2E, 0x30, 0x32, 0x62, 0x64, 0x66, 0x68 };
+#define SCH5636_REG_FAN_CTRL(i)		(0x880 + (i))
+/* FAULT in datasheet, but acts as an alarm */
+#define SCH5636_FAN_ALARM		0x04
+#define SCH5636_FAN_NOT_PRESENT		0x08
+#define SCH5636_FAN_DEACTIVATED		0x80
+
+
+struct sch5636_data {
+	unsigned short addr;
+	struct device *hwmon_dev;
+	struct sch56xx_watchdog_data *watchdog;
+
+	struct mutex update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	u8 in[SCH5636_NO_INS];
+	u8 temp_val[SCH5636_NO_TEMPS];
+	u8 temp_ctrl[SCH5636_NO_TEMPS];
+	u16 fan_val[SCH5636_NO_FANS];
+	u8 fan_ctrl[SCH5636_NO_FANS];
+};
+
+static struct sch5636_data *sch5636_update_device(struct device *dev)
+{
+	struct sch5636_data *data = dev_get_drvdata(dev);
+	struct sch5636_data *ret = data;
+	int i, val;
+
+	mutex_lock(&data->update_lock);
+
+	/* Cache the values for 1 second */
+	if (data->valid && !time_after(jiffies, data->last_updated + HZ))
+		goto abort;
+
+	for (i = 0; i < SCH5636_NO_INS; i++) {
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_IN_VAL[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->in[i] = val;
+	}
+
+	for (i = 0; i < SCH5636_NO_TEMPS; i++) {
+		if (data->temp_ctrl[i] & SCH5636_TEMP_DEACTIVATED)
+			continue;
+
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_TEMP_VAL[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp_val[i] = val;
+
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_TEMP_CTRL(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp_ctrl[i] = val;
+		/* Alarms need to be explicitly write-cleared */
+		if (val & SCH5636_TEMP_ALARM) {
+			sch56xx_write_virtual_reg(data->addr,
+						SCH5636_REG_TEMP_CTRL(i), val);
+		}
+	}
+
+	for (i = 0; i < SCH5636_NO_FANS; i++) {
+		if (data->fan_ctrl[i] & SCH5636_FAN_DEACTIVATED)
+			continue;
+
+		val = sch56xx_read_virtual_reg16(data->addr,
+						 SCH5636_REG_FAN_VAL[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->fan_val[i] = val;
+
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_FAN_CTRL(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->fan_ctrl[i] = val;
+		/* Alarms need to be explicitly write-cleared */
+		if (val & SCH5636_FAN_ALARM) {
+			sch56xx_write_virtual_reg(data->addr,
+						SCH5636_REG_FAN_CTRL(i), val);
+		}
+	}
+
+	data->last_updated = jiffies;
+	data->valid = 1;
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static int reg_to_rpm(u16 reg)
+{
+	if (reg == 0)
+		return -EIO;
+	if (reg == 0xffff)
+		return 0;
+
+	return 5400540 / reg;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+	char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
+}
+
+static ssize_t show_in_value(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = DIV_ROUND_CLOSEST(
+		data->in[attr->index] * SCH5636_REG_IN_FACTORS[attr->index],
+		255);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_in_label(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			SCH5636_IN_LABELS[attr->index]);
+}
+
+static ssize_t show_temp_value(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = (data->temp_val[attr->index] - 64) * 1000;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_WORKING) ? 0 : 1;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_ALARM) ? 1 : 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan_value(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = reg_to_rpm(data->fan_val[attr->index]);
+	if (val < 0)
+		return val;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = (data->fan_ctrl[attr->index] & SCH5636_FAN_NOT_PRESENT) ? 1 : 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+	*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sch5636_data *data = sch5636_update_device(dev);
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = (data->fan_ctrl[attr->index] & SCH5636_FAN_ALARM) ? 1 : 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static struct sensor_device_attribute sch5636_attr[] = {
+	SENSOR_ATTR(name, 0444, show_name, NULL, 0),
+	SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
+	SENSOR_ATTR(in0_label, 0444, show_in_label, NULL, 0),
+	SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
+	SENSOR_ATTR(in1_label, 0444, show_in_label, NULL, 1),
+	SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
+	SENSOR_ATTR(in2_label, 0444, show_in_label, NULL, 2),
+	SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
+	SENSOR_ATTR(in3_label, 0444, show_in_label, NULL, 3),
+	SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
+	SENSOR_ATTR(in4_label, 0444, show_in_label, NULL, 4),
+};
+
+static struct sensor_device_attribute sch5636_temp_attr[] = {
+	SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+	SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
+	SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
+	SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+	SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
+	SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
+	SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
+	SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
+	SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
+	SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
+	SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
+	SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
+	SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
+	SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
+	SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+	SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
+	SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
+	SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
+	SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
+	SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
+	SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
+	SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
+	SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
+	SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
+	SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
+	SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
+	SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
+	SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
+	SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
+	SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
+	SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
+	SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
+	SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
+	SENSOR_ATTR(temp12_input, 0444, show_temp_value, NULL, 11),
+	SENSOR_ATTR(temp12_fault, 0444, show_temp_fault, NULL, 11),
+	SENSOR_ATTR(temp12_alarm, 0444, show_temp_alarm, NULL, 11),
+	SENSOR_ATTR(temp13_input, 0444, show_temp_value, NULL, 12),
+	SENSOR_ATTR(temp13_fault, 0444, show_temp_fault, NULL, 12),
+	SENSOR_ATTR(temp13_alarm, 0444, show_temp_alarm, NULL, 12),
+	SENSOR_ATTR(temp14_input, 0444, show_temp_value, NULL, 13),
+	SENSOR_ATTR(temp14_fault, 0444, show_temp_fault, NULL, 13),
+	SENSOR_ATTR(temp14_alarm, 0444, show_temp_alarm, NULL, 13),
+	SENSOR_ATTR(temp15_input, 0444, show_temp_value, NULL, 14),
+	SENSOR_ATTR(temp15_fault, 0444, show_temp_fault, NULL, 14),
+	SENSOR_ATTR(temp15_alarm, 0444, show_temp_alarm, NULL, 14),
+	SENSOR_ATTR(temp16_input, 0444, show_temp_value, NULL, 15),
+	SENSOR_ATTR(temp16_fault, 0444, show_temp_fault, NULL, 15),
+	SENSOR_ATTR(temp16_alarm, 0444, show_temp_alarm, NULL, 15),
+};
+
+static struct sensor_device_attribute sch5636_fan_attr[] = {
+	SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
+	SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
+	SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
+	SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
+	SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
+	SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
+	SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
+	SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
+	SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
+	SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
+	SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
+	SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
+	SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
+	SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
+	SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
+	SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
+	SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
+	SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
+	SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
+	SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
+	SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
+	SENSOR_ATTR(fan8_input, 0444, show_fan_value, NULL, 7),
+	SENSOR_ATTR(fan8_fault, 0444, show_fan_fault, NULL, 7),
+	SENSOR_ATTR(fan8_alarm, 0444, show_fan_alarm, NULL, 7),
+};
+
+static int sch5636_remove(struct platform_device *pdev)
+{
+	struct sch5636_data *data = platform_get_drvdata(pdev);
+	int i;
+
+	if (data->watchdog)
+		sch56xx_watchdog_unregister(data->watchdog);
+
+	if (data->hwmon_dev)
+		hwmon_device_unregister(data->hwmon_dev);
+
+	for (i = 0; i < ARRAY_SIZE(sch5636_attr); i++)
+		device_remove_file(&pdev->dev, &sch5636_attr[i].dev_attr);
+
+	for (i = 0; i < SCH5636_NO_TEMPS * 3; i++)
+		device_remove_file(&pdev->dev,
+				   &sch5636_temp_attr[i].dev_attr);
+
+	for (i = 0; i < SCH5636_NO_FANS * 3; i++)
+		device_remove_file(&pdev->dev,
+				   &sch5636_fan_attr[i].dev_attr);
+
+	return 0;
+}
+
+static int sch5636_probe(struct platform_device *pdev)
+{
+	struct sch5636_data *data;
+	int i, err, val, revision[2];
+	char id[4];
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5636_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	for (i = 0; i < 3; i++) {
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_FUJITSU_ID + i);
+		if (val < 0) {
+			pr_err("Could not read Fujitsu id byte at %#x\n",
+				SCH5636_REG_FUJITSU_ID + i);
+			err = val;
+			goto error;
+		}
+		id[i] = val;
+	}
+	id[i] = '\0';
+
+	if (strcmp(id, "THS")) {
+		pr_err("Unknown Fujitsu id: %02x%02x%02x\n",
+		       id[0], id[1], id[2]);
+		err = -ENODEV;
+		goto error;
+	}
+
+	for (i = 0; i < 2; i++) {
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_FUJITSU_REV + i);
+		if (val < 0) {
+			err = val;
+			goto error;
+		}
+		revision[i] = val;
+	}
+	pr_info("Found %s chip at %#hx, revison: %d.%02d\n", DEVNAME,
+		data->addr, revision[0], revision[1]);
+
+	/* Read all temp + fan ctrl registers to determine which are active */
+	for (i = 0; i < SCH5636_NO_TEMPS; i++) {
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_TEMP_CTRL(i));
+		if (unlikely(val < 0)) {
+			err = val;
+			goto error;
+		}
+		data->temp_ctrl[i] = val;
+	}
+
+	for (i = 0; i < SCH5636_NO_FANS; i++) {
+		val = sch56xx_read_virtual_reg(data->addr,
+					       SCH5636_REG_FAN_CTRL(i));
+		if (unlikely(val < 0)) {
+			err = val;
+			goto error;
+		}
+		data->fan_ctrl[i] = val;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sch5636_attr); i++) {
+		err = device_create_file(&pdev->dev,
+					 &sch5636_attr[i].dev_attr);
+		if (err)
+			goto error;
+	}
+
+	for (i = 0; i < (SCH5636_NO_TEMPS * 3); i++) {
+		if (data->temp_ctrl[i/3] & SCH5636_TEMP_DEACTIVATED)
+			continue;
+
+		err = device_create_file(&pdev->dev,
+					&sch5636_temp_attr[i].dev_attr);
+		if (err)
+			goto error;
+	}
+
+	for (i = 0; i < (SCH5636_NO_FANS * 3); i++) {
+		if (data->fan_ctrl[i/3] & SCH5636_FAN_DEACTIVATED)
+			continue;
+
+		err = device_create_file(&pdev->dev,
+					&sch5636_fan_attr[i].dev_attr);
+		if (err)
+			goto error;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		data->hwmon_dev = NULL;
+		goto error;
+	}
+
+	/* Note failing to register the watchdog is not a fatal error */
+	data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
+					(revision[0] << 8) | revision[1],
+					&data->update_lock, 0);
+
+	return 0;
+
+error:
+	sch5636_remove(pdev);
+	return err;
+}
+
+static struct platform_driver sch5636_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= sch5636_probe,
+	.remove		= sch5636_remove,
+};
+
+module_platform_driver(sch5636_driver);
+
+MODULE_DESCRIPTION("SMSC SCH5636 Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
new file mode 100644
index 0000000..7386819
--- /dev/null
+++ b/drivers/hwmon/sch56xx-common.c
@@ -0,0 +1,619 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+#include "sch56xx-common.h"
+
+/* Insmod parameters */
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define SIO_SCH56XX_LD_EM	0x0C	/* Embedded uController Logical Dev */
+#define SIO_UNLOCK_KEY		0x55	/* Key to enable Super-I/O */
+#define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x66	/* Logical device address (2 bytes) */
+
+#define SIO_SCH5627_ID		0xC6	/* Chipset ID */
+#define SIO_SCH5636_ID		0xC7	/* Chipset ID */
+
+#define REGION_LENGTH		10
+
+#define SCH56XX_CMD_READ	0x02
+#define SCH56XX_CMD_WRITE	0x03
+
+/* Watchdog registers */
+#define SCH56XX_REG_WDOG_PRESET		0x58B
+#define SCH56XX_REG_WDOG_CONTROL	0x58C
+#define SCH56XX_WDOG_TIME_BASE_SEC	0x01
+#define SCH56XX_REG_WDOG_OUTPUT_ENABLE	0x58E
+#define SCH56XX_WDOG_OUTPUT_ENABLE	0x02
+
+struct sch56xx_watchdog_data {
+	u16 addr;
+	struct mutex *io_lock;
+	struct kref kref;
+	struct watchdog_info wdinfo;
+	struct watchdog_device wddev;
+	u8 watchdog_preset;
+	u8 watchdog_control;
+	u8 watchdog_output_enable;
+};
+
+static struct platform_device *sch56xx_pdev;
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+	outb(reg, base);
+	return inb(base + 1);
+}
+
+static inline int superio_enter(int base)
+{
+	/* Don't step on other drivers' I/O space by accident */
+	if (!request_muxed_region(base, 2, "sch56xx")) {
+		pr_err("I/O address 0x%04x already in use\n", base);
+		return -EBUSY;
+	}
+
+	outb(SIO_UNLOCK_KEY, base);
+
+	return 0;
+}
+
+static inline void superio_select(int base, int ld)
+{
+	outb(SIO_REG_LDSEL, base);
+	outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+	outb(SIO_LOCK_KEY, base);
+	release_region(base, 2);
+}
+
+static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
+{
+	u8 val;
+	int i;
+	/*
+	 * According to SMSC for the commands we use the maximum time for
+	 * the EM to respond is 15 ms, but testing shows in practice it
+	 * responds within 15-32 reads, so we first busy poll, and if
+	 * that fails sleep a bit and try again until we are way past
+	 * the 15 ms maximum response time.
+	 */
+	const int max_busy_polls = 64;
+	const int max_lazy_polls = 32;
+
+	/* (Optional) Write-Clear the EC to Host Mailbox Register */
+	val = inb(addr + 1);
+	outb(val, addr + 1);
+
+	/* Set Mailbox Address Pointer to first location in Region 1 */
+	outb(0x00, addr + 2);
+	outb(0x80, addr + 3);
+
+	/* Write Request Packet Header */
+	outb(cmd, addr + 4); /* VREG Access Type read:0x02 write:0x03 */
+	outb(0x01, addr + 5); /* # of Entries: 1 Byte (8-bit) */
+	outb(0x04, addr + 2); /* Mailbox AP to first data entry loc. */
+
+	/* Write Value field */
+	if (cmd == SCH56XX_CMD_WRITE)
+		outb(v, addr + 4);
+
+	/* Write Address field */
+	outb(reg & 0xff, addr + 6);
+	outb(reg >> 8, addr + 7);
+
+	/* Execute the Random Access Command */
+	outb(0x01, addr); /* Write 01h to the Host-to-EC register */
+
+	/* EM Interface Polling "Algorithm" */
+	for (i = 0; i < max_busy_polls + max_lazy_polls; i++) {
+		if (i >= max_busy_polls)
+			msleep(1);
+		/* Read Interrupt source Register */
+		val = inb(addr + 8);
+		/* Write Clear the interrupt source bits */
+		if (val)
+			outb(val, addr + 8);
+		/* Command Completed ? */
+		if (val & 0x01)
+			break;
+	}
+	if (i == max_busy_polls + max_lazy_polls) {
+		pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+		       reg, 1);
+		return -EIO;
+	}
+
+	/*
+	 * According to SMSC we may need to retry this, but sofar I've always
+	 * seen this succeed in 1 try.
+	 */
+	for (i = 0; i < max_busy_polls; i++) {
+		/* Read EC-to-Host Register */
+		val = inb(addr + 1);
+		/* Command Completed ? */
+		if (val == 0x01)
+			break;
+
+		if (i == 0)
+			pr_warn("EC reports: 0x%02x reading virtual register 0x%04hx\n",
+				(unsigned int)val, reg);
+	}
+	if (i == max_busy_polls) {
+		pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+		       reg, 2);
+		return -EIO;
+	}
+
+	/*
+	 * According to the SMSC app note we should now do:
+	 *
+	 * Set Mailbox Address Pointer to first location in Region 1 *
+	 * outb(0x00, addr + 2);
+	 * outb(0x80, addr + 3);
+	 *
+	 * But if we do that things don't work, so let's not.
+	 */
+
+	/* Read Value field */
+	if (cmd == SCH56XX_CMD_READ)
+		return inb(addr + 4);
+
+	return 0;
+}
+
+int sch56xx_read_virtual_reg(u16 addr, u16 reg)
+{
+	return sch56xx_send_cmd(addr, SCH56XX_CMD_READ, reg, 0);
+}
+EXPORT_SYMBOL(sch56xx_read_virtual_reg);
+
+int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val)
+{
+	return sch56xx_send_cmd(addr, SCH56XX_CMD_WRITE, reg, val);
+}
+EXPORT_SYMBOL(sch56xx_write_virtual_reg);
+
+int sch56xx_read_virtual_reg16(u16 addr, u16 reg)
+{
+	int lsb, msb;
+
+	/* Read LSB first, this will cause the matching MSB to be latched */
+	lsb = sch56xx_read_virtual_reg(addr, reg);
+	if (lsb < 0)
+		return lsb;
+
+	msb = sch56xx_read_virtual_reg(addr, reg + 1);
+	if (msb < 0)
+		return msb;
+
+	return lsb | (msb << 8);
+}
+EXPORT_SYMBOL(sch56xx_read_virtual_reg16);
+
+int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
+			       int high_nibble)
+{
+	int msb, lsn;
+
+	/* Read MSB first, this will cause the matching LSN to be latched */
+	msb = sch56xx_read_virtual_reg(addr, msb_reg);
+	if (msb < 0)
+		return msb;
+
+	lsn = sch56xx_read_virtual_reg(addr, lsn_reg);
+	if (lsn < 0)
+		return lsn;
+
+	if (high_nibble)
+		return (msb << 4) | (lsn >> 4);
+	else
+		return (msb << 4) | (lsn & 0x0f);
+}
+EXPORT_SYMBOL(sch56xx_read_virtual_reg12);
+
+/*
+ * Watchdog routines
+ */
+
+/* Release our data struct when we're unregistered *and*
+   all references to our watchdog device are released */
+static void watchdog_release_resources(struct kref *r)
+{
+	struct sch56xx_watchdog_data *data =
+		container_of(r, struct sch56xx_watchdog_data, kref);
+	kfree(data);
+}
+
+static int watchdog_set_timeout(struct watchdog_device *wddev,
+				unsigned int timeout)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+	unsigned int resolution;
+	u8 control;
+	int ret;
+
+	/* 1 second or 60 second resolution? */
+	if (timeout <= 255)
+		resolution = 1;
+	else
+		resolution = 60;
+
+	if (timeout < resolution || timeout > (resolution * 255))
+		return -EINVAL;
+
+	if (resolution == 1)
+		control = data->watchdog_control | SCH56XX_WDOG_TIME_BASE_SEC;
+	else
+		control = data->watchdog_control & ~SCH56XX_WDOG_TIME_BASE_SEC;
+
+	if (data->watchdog_control != control) {
+		mutex_lock(data->io_lock);
+		ret = sch56xx_write_virtual_reg(data->addr,
+						SCH56XX_REG_WDOG_CONTROL,
+						control);
+		mutex_unlock(data->io_lock);
+		if (ret)
+			return ret;
+
+		data->watchdog_control = control;
+	}
+
+	/*
+	 * Remember new timeout value, but do not write as that (re)starts
+	 * the watchdog countdown.
+	 */
+	data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
+	wddev->timeout = data->watchdog_preset * resolution;
+
+	return 0;
+}
+
+static int watchdog_start(struct watchdog_device *wddev)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+	int ret;
+	u8 val;
+
+	/*
+	 * The sch56xx's watchdog cannot really be started / stopped
+	 * it is always running, but we can avoid the timer expiring
+	 * from causing a system reset by clearing the output enable bit.
+	 *
+	 * The sch56xx's watchdog will set the watchdog event bit, bit 0
+	 * of the second interrupt source register (at base-address + 9),
+	 * when the timer expires.
+	 *
+	 * This will only cause a system reset if the 0-1 flank happens when
+	 * output enable is true. Setting output enable after the flank will
+	 * not cause a reset, nor will the timer expiring a second time.
+	 * This means we must clear the watchdog event bit in case it is set.
+	 *
+	 * The timer may still be running (after a recent watchdog_stop) and
+	 * mere milliseconds away from expiring, so the timer must be reset
+	 * first!
+	 */
+
+	mutex_lock(data->io_lock);
+
+	/* 1. Reset the watchdog countdown counter */
+	ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET,
+					data->watchdog_preset);
+	if (ret)
+		goto leave;
+
+	/* 2. Enable output */
+	val = data->watchdog_output_enable | SCH56XX_WDOG_OUTPUT_ENABLE;
+	ret = sch56xx_write_virtual_reg(data->addr,
+					SCH56XX_REG_WDOG_OUTPUT_ENABLE, val);
+	if (ret)
+		goto leave;
+
+	data->watchdog_output_enable = val;
+
+	/* 3. Clear the watchdog event bit if set */
+	val = inb(data->addr + 9);
+	if (val & 0x01)
+		outb(0x01, data->addr + 9);
+
+leave:
+	mutex_unlock(data->io_lock);
+	return ret;
+}
+
+static int watchdog_trigger(struct watchdog_device *wddev)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+	int ret;
+
+	/* Reset the watchdog countdown counter */
+	mutex_lock(data->io_lock);
+	ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET,
+					data->watchdog_preset);
+	mutex_unlock(data->io_lock);
+
+	return ret;
+}
+
+static int watchdog_stop(struct watchdog_device *wddev)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+	int ret = 0;
+	u8 val;
+
+	val = data->watchdog_output_enable & ~SCH56XX_WDOG_OUTPUT_ENABLE;
+	mutex_lock(data->io_lock);
+	ret = sch56xx_write_virtual_reg(data->addr,
+					SCH56XX_REG_WDOG_OUTPUT_ENABLE, val);
+	mutex_unlock(data->io_lock);
+	if (ret)
+		return ret;
+
+	data->watchdog_output_enable = val;
+	return 0;
+}
+
+static void watchdog_ref(struct watchdog_device *wddev)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+
+	kref_get(&data->kref);
+}
+
+static void watchdog_unref(struct watchdog_device *wddev)
+{
+	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
+
+	kref_put(&data->kref, watchdog_release_resources);
+}
+
+static const struct watchdog_ops watchdog_ops = {
+	.owner		= THIS_MODULE,
+	.start		= watchdog_start,
+	.stop		= watchdog_stop,
+	.ping		= watchdog_trigger,
+	.set_timeout	= watchdog_set_timeout,
+	.ref		= watchdog_ref,
+	.unref		= watchdog_unref,
+};
+
+struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
+	u16 addr, u32 revision, struct mutex *io_lock, int check_enabled)
+{
+	struct sch56xx_watchdog_data *data;
+	int err, control, output_enable;
+
+	/* Cache the watchdog registers */
+	mutex_lock(io_lock);
+	control =
+		sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_CONTROL);
+	output_enable =
+		sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_OUTPUT_ENABLE);
+	mutex_unlock(io_lock);
+
+	if (control < 0)
+		return NULL;
+	if (output_enable < 0)
+		return NULL;
+	if (check_enabled && !(output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) {
+		pr_warn("Watchdog not enabled by BIOS, not registering\n");
+		return NULL;
+	}
+
+	data = kzalloc(sizeof(struct sch56xx_watchdog_data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->addr = addr;
+	data->io_lock = io_lock;
+	kref_init(&data->kref);
+
+	strlcpy(data->wdinfo.identity, "sch56xx watchdog",
+		sizeof(data->wdinfo.identity));
+	data->wdinfo.firmware_version = revision;
+	data->wdinfo.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT;
+	if (!nowayout)
+		data->wdinfo.options |= WDIOF_MAGICCLOSE;
+
+	data->wddev.info = &data->wdinfo;
+	data->wddev.ops = &watchdog_ops;
+	data->wddev.parent = parent;
+	data->wddev.timeout = 60;
+	data->wddev.min_timeout = 1;
+	data->wddev.max_timeout = 255 * 60;
+	if (nowayout)
+		set_bit(WDOG_NO_WAY_OUT, &data->wddev.status);
+	if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)
+		set_bit(WDOG_ACTIVE, &data->wddev.status);
+
+	/* Since the watchdog uses a downcounter there is no register to read
+	   the BIOS set timeout from (if any was set at all) ->
+	   Choose a preset which will give us a 1 minute timeout */
+	if (control & SCH56XX_WDOG_TIME_BASE_SEC)
+		data->watchdog_preset = 60; /* seconds */
+	else
+		data->watchdog_preset = 1; /* minute */
+
+	data->watchdog_control = control;
+	data->watchdog_output_enable = output_enable;
+
+	watchdog_set_drvdata(&data->wddev, data);
+	err = watchdog_register_device(&data->wddev);
+	if (err) {
+		pr_err("Registering watchdog chardev: %d\n", err);
+		kfree(data);
+		return NULL;
+	}
+
+	return data;
+}
+EXPORT_SYMBOL(sch56xx_watchdog_register);
+
+void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
+{
+	watchdog_unregister_device(&data->wddev);
+	kref_put(&data->kref, watchdog_release_resources);
+	/* Don't touch data after this it may have been free-ed! */
+}
+EXPORT_SYMBOL(sch56xx_watchdog_unregister);
+
+/*
+ * platform dev find, add and remove functions
+ */
+
+static int __init sch56xx_find(int sioaddr, const char **name)
+{
+	u8 devid;
+	unsigned short address;
+	int err;
+
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
+
+	devid = superio_inb(sioaddr, SIO_REG_DEVID);
+	switch (devid) {
+	case SIO_SCH5627_ID:
+		*name = "sch5627";
+		break;
+	case SIO_SCH5636_ID:
+		*name = "sch5636";
+		break;
+	default:
+		pr_debug("Unsupported device id: 0x%02x\n",
+			 (unsigned int)devid);
+		err = -ENODEV;
+		goto exit;
+	}
+
+	superio_select(sioaddr, SIO_SCH56XX_LD_EM);
+
+	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+		pr_warn("Device not activated\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/*
+	 * Warning the order of the low / high byte is the other way around
+	 * as on most other superio devices!!
+	 */
+	address = superio_inb(sioaddr, SIO_REG_ADDR) |
+		   superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
+	if (address == 0) {
+		pr_warn("Base address not set\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	err = address;
+
+exit:
+	superio_exit(sioaddr);
+	return err;
+}
+
+static int __init sch56xx_device_add(int address, const char *name)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + REGION_LENGTH - 1,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	sch56xx_pdev = platform_device_alloc(name, address);
+	if (!sch56xx_pdev)
+		return -ENOMEM;
+
+	res.name = sch56xx_pdev->name;
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit_device_put;
+
+	err = platform_device_add_resources(sch56xx_pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(sch56xx_pdev);
+	if (err) {
+		pr_err("Device addition failed\n");
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(sch56xx_pdev);
+
+	return err;
+}
+
+static int __init sch56xx_init(void)
+{
+	int address;
+	const char *name = NULL;
+
+	address = sch56xx_find(0x4e, &name);
+	if (address < 0)
+		address = sch56xx_find(0x2e, &name);
+	if (address < 0)
+		return address;
+
+	return sch56xx_device_add(address, name);
+}
+
+static void __exit sch56xx_exit(void)
+{
+	platform_device_unregister(sch56xx_pdev);
+}
+
+MODULE_DESCRIPTION("SMSC SCH56xx Hardware Monitoring Common Code");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(sch56xx_init);
+module_exit(sch56xx_exit);
diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h
new file mode 100644
index 0000000..704ea2c
--- /dev/null
+++ b/drivers/hwmon/sch56xx-common.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include <linux/mutex.h>
+
+struct sch56xx_watchdog_data;
+
+int sch56xx_read_virtual_reg(u16 addr, u16 reg);
+int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val);
+int sch56xx_read_virtual_reg16(u16 addr, u16 reg);
+int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
+			       int high_nibble);
+
+struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
+	u16 addr, u32 revision, struct mutex *io_lock, int check_enabled);
+void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data);
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c
new file mode 100644
index 0000000..6827169
--- /dev/null
+++ b/drivers/hwmon/scpi-hwmon.c
@@ -0,0 +1,290 @@
+/*
+ * System Control and Power Interface(SCPI) based hwmon sensor driver
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Punit Agrawal <punit.agrawal@arm.com>
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/scpi_protocol.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+
+struct sensor_data {
+	struct scpi_sensor_info info;
+	struct device_attribute dev_attr_input;
+	struct device_attribute dev_attr_label;
+	char input[20];
+	char label[20];
+};
+
+struct scpi_thermal_zone {
+	struct list_head list;
+	int sensor_id;
+	struct scpi_sensors *scpi_sensors;
+	struct thermal_zone_device *tzd;
+};
+
+struct scpi_sensors {
+	struct scpi_ops *scpi_ops;
+	struct sensor_data *data;
+	struct list_head thermal_zones;
+	struct attribute **attrs;
+	struct attribute_group group;
+	const struct attribute_group *groups[2];
+};
+
+static int scpi_read_temp(void *dev, int *temp)
+{
+	struct scpi_thermal_zone *zone = dev;
+	struct scpi_sensors *scpi_sensors = zone->scpi_sensors;
+	struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
+	struct sensor_data *sensor = &scpi_sensors->data[zone->sensor_id];
+	u32 value;
+	int ret;
+
+	ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
+	if (ret)
+		return ret;
+
+	*temp = value;
+	return 0;
+}
+
+/* hwmon callback functions */
+static ssize_t
+scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scpi_sensors *scpi_sensors = dev_get_drvdata(dev);
+	struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
+	struct sensor_data *sensor;
+	u32 value;
+	int ret;
+
+	sensor = container_of(attr, struct sensor_data, dev_attr_input);
+
+	ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t
+scpi_show_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_data *sensor;
+
+	sensor = container_of(attr, struct sensor_data, dev_attr_label);
+
+	return sprintf(buf, "%s\n", sensor->info.name);
+}
+
+static void
+unregister_thermal_zones(struct platform_device *pdev,
+			 struct scpi_sensors *scpi_sensors)
+{
+	struct list_head *pos;
+
+	list_for_each(pos, &scpi_sensors->thermal_zones) {
+		struct scpi_thermal_zone *zone;
+
+		zone = list_entry(pos, struct scpi_thermal_zone, list);
+		thermal_zone_of_sensor_unregister(&pdev->dev, zone->tzd);
+	}
+}
+
+static struct thermal_zone_of_device_ops scpi_sensor_ops = {
+	.get_temp = scpi_read_temp,
+};
+
+static int scpi_hwmon_probe(struct platform_device *pdev)
+{
+	u16 nr_sensors, i;
+	int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0;
+	struct scpi_ops *scpi_ops;
+	struct device *hwdev, *dev = &pdev->dev;
+	struct scpi_sensors *scpi_sensors;
+	int ret, idx;
+
+	scpi_ops = get_scpi_ops();
+	if (!scpi_ops)
+		return -EPROBE_DEFER;
+
+	ret = scpi_ops->sensor_get_capability(&nr_sensors);
+	if (ret)
+		return ret;
+
+	if (!nr_sensors)
+		return -ENODEV;
+
+	scpi_sensors = devm_kzalloc(dev, sizeof(*scpi_sensors), GFP_KERNEL);
+	if (!scpi_sensors)
+		return -ENOMEM;
+
+	scpi_sensors->data = devm_kcalloc(dev, nr_sensors,
+				   sizeof(*scpi_sensors->data), GFP_KERNEL);
+	if (!scpi_sensors->data)
+		return -ENOMEM;
+
+	scpi_sensors->attrs = devm_kcalloc(dev, (nr_sensors * 2) + 1,
+				   sizeof(*scpi_sensors->attrs), GFP_KERNEL);
+	if (!scpi_sensors->attrs)
+		return -ENOMEM;
+
+	scpi_sensors->scpi_ops = scpi_ops;
+
+	for (i = 0, idx = 0; i < nr_sensors; i++) {
+		struct sensor_data *sensor = &scpi_sensors->data[idx];
+
+		ret = scpi_ops->sensor_get_info(i, &sensor->info);
+		if (ret)
+			return ret;
+
+		switch (sensor->info.class) {
+		case TEMPERATURE:
+			snprintf(sensor->input, sizeof(sensor->input),
+				 "temp%d_input", num_temp + 1);
+			snprintf(sensor->label, sizeof(sensor->input),
+				 "temp%d_label", num_temp + 1);
+			num_temp++;
+			break;
+		case VOLTAGE:
+			snprintf(sensor->input, sizeof(sensor->input),
+				 "in%d_input", num_volt);
+			snprintf(sensor->label, sizeof(sensor->input),
+				 "in%d_label", num_volt);
+			num_volt++;
+			break;
+		case CURRENT:
+			snprintf(sensor->input, sizeof(sensor->input),
+				 "curr%d_input", num_current + 1);
+			snprintf(sensor->label, sizeof(sensor->input),
+				 "curr%d_label", num_current + 1);
+			num_current++;
+			break;
+		case POWER:
+			snprintf(sensor->input, sizeof(sensor->input),
+				 "power%d_input", num_power + 1);
+			snprintf(sensor->label, sizeof(sensor->input),
+				 "power%d_label", num_power + 1);
+			num_power++;
+			break;
+		default:
+			continue;
+		}
+
+		sensor->dev_attr_input.attr.mode = S_IRUGO;
+		sensor->dev_attr_input.show = scpi_show_sensor;
+		sensor->dev_attr_input.attr.name = sensor->input;
+
+		sensor->dev_attr_label.attr.mode = S_IRUGO;
+		sensor->dev_attr_label.show = scpi_show_label;
+		sensor->dev_attr_label.attr.name = sensor->label;
+
+		scpi_sensors->attrs[idx << 1] = &sensor->dev_attr_input.attr;
+		scpi_sensors->attrs[(idx << 1) + 1] = &sensor->dev_attr_label.attr;
+
+		sysfs_attr_init(scpi_sensors->attrs[idx << 1]);
+		sysfs_attr_init(scpi_sensors->attrs[(idx << 1) + 1]);
+		idx++;
+	}
+
+	scpi_sensors->group.attrs = scpi_sensors->attrs;
+	scpi_sensors->groups[0] = &scpi_sensors->group;
+
+	platform_set_drvdata(pdev, scpi_sensors);
+
+	hwdev = devm_hwmon_device_register_with_groups(dev,
+			"scpi_sensors", scpi_sensors, scpi_sensors->groups);
+
+	if (IS_ERR(hwdev))
+		return PTR_ERR(hwdev);
+
+	/*
+	 * Register the temperature sensors with the thermal framework
+	 * to allow their usage in setting up the thermal zones from
+	 * device tree.
+	 *
+	 * NOTE: Not all temperature sensors maybe used for thermal
+	 * control
+	 */
+	INIT_LIST_HEAD(&scpi_sensors->thermal_zones);
+	for (i = 0; i < nr_sensors; i++) {
+		struct sensor_data *sensor = &scpi_sensors->data[i];
+		struct scpi_thermal_zone *zone;
+
+		if (sensor->info.class != TEMPERATURE)
+			continue;
+
+		zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL);
+		if (!zone) {
+			ret = -ENOMEM;
+			goto unregister_tzd;
+		}
+
+		zone->sensor_id = i;
+		zone->scpi_sensors = scpi_sensors;
+		zone->tzd = thermal_zone_of_sensor_register(dev,
+				sensor->info.sensor_id, zone, &scpi_sensor_ops);
+		/*
+		 * The call to thermal_zone_of_sensor_register returns
+		 * an error for sensors that are not associated with
+		 * any thermal zones or if the thermal subsystem is
+		 * not configured.
+		 */
+		if (IS_ERR(zone->tzd)) {
+			devm_kfree(dev, zone);
+			continue;
+		}
+		list_add(&zone->list, &scpi_sensors->thermal_zones);
+	}
+
+	return 0;
+
+unregister_tzd:
+	unregister_thermal_zones(pdev, scpi_sensors);
+	return ret;
+}
+
+static int scpi_hwmon_remove(struct platform_device *pdev)
+{
+	struct scpi_sensors *scpi_sensors = platform_get_drvdata(pdev);
+
+	unregister_thermal_zones(pdev, scpi_sensors);
+
+	return 0;
+}
+
+static const struct of_device_id scpi_of_match[] = {
+	{.compatible = "arm,scpi-sensors"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, scpi_of_match);
+
+static struct platform_driver scpi_hwmon_platdrv = {
+	.driver = {
+		.name	= "scpi-hwmon",
+		.owner	= THIS_MODULE,
+		.of_match_table = scpi_of_match,
+	},
+	.probe		= scpi_hwmon_probe,
+	.remove		= scpi_hwmon_remove,
+};
+module_platform_driver(scpi_hwmon_platdrv);
+
+MODULE_AUTHOR("Punit Agrawal <punit.agrawal@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI HWMON interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
new file mode 100644
index 0000000..a2fdbb7
--- /dev/null
+++ b/drivers/hwmon/sht15.c
@@ -0,0 +1,1086 @@
+/*
+ * sht15.c - support for the SHT15 Temperature and Humidity Sensor
+ *
+ * Portions Copyright (c) 2010-2012 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
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/sht15.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/bitrev.h>
+
+/* 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
+
+/* 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 */
+
+/* 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
+
+/* List of supported chips */
+enum sht15_chips { sht10, sht11, sht15, sht71, sht75 };
+
+/* 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
+ * @vdd:	supply voltage in microvolts
+ * @d1:		see data sheet
+ */
+struct sht15_temppair {
+	int vdd; /* microvolts */
+	int d1;
+};
+
+/* Table 9 from datasheet - relates temperature calculation to supply voltage */
+static const struct sht15_temppair temppoints[] = {
+	{ 2500000, -39400 },
+	{ 3000000, -39600 },
+	{ 3500000, -39700 },
+	{ 4000000, -39800 },
+	{ 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.
+ * @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;
+	struct work_struct		read_work;
+	wait_queue_head_t		wait_queue;
+	uint16_t			val_temp;
+	uint16_t			val_humid;
+	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;
+	bool				supply_uv_valid;
+	struct work_struct		update_supply_work;
+	atomic_t			interrupt_handled;
+};
+
+/**
+ * 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 = bitrev8(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
+ *
+ * This implements section 3.4 of the data sheet
+ */
+static int sht15_connection_reset(struct sht15_data *data)
+{
+	int i, err;
+
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
+	ndelay(SHT15_TSCKL);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	for (i = 0; i < 9; ++i) {
+		gpio_set_value(data->pdata->gpio_sck, 1);
+		ndelay(SHT15_TSCKH);
+		gpio_set_value(data->pdata->gpio_sck, 0);
+		ndelay(SHT15_TSCKL);
+	}
+	return 0;
+}
+
+/**
+ * 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);
+	ndelay(SHT15_TSCKH);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL); /* clock low time */
+}
+
+/**
+ * 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 int sht15_transmission_start(struct sht15_data *data)
+{
+	int err;
+
+	/* ensure data is high and output */
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSCKH);
+	gpio_set_value(data->pdata->gpio_data, 0);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSCKH);
+	gpio_set_value(data->pdata->gpio_data, 1);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	return 0;
+}
+
+/**
+ * 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)
+{
+	int err;
+
+	err = gpio_direction_input(data->pdata->gpio_data);
+	if (err)
+		return err;
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSCKH);
+	if (gpio_get_value(data->pdata->gpio_data)) {
+		gpio_set_value(data->pdata->gpio_sck, 0);
+		dev_err(data->dev, "Command not acknowledged\n");
+		err = sht15_connection_reset(data);
+		if (err)
+			return err;
+		return -EIO;
+	}
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	return 0;
+}
+
+/**
+ * sht15_send_cmd() - Sends a command to the device.
+ * @data:	device state
+ * @cmd:	command byte to be sent
+ *
+ * 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 err;
+
+	err = sht15_transmission_start(data);
+	if (err)
+		return err;
+	sht15_send_byte(data, cmd);
+	return sht15_wait_for_response(data);
+}
+
+/**
+ * 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 int sht15_ack(struct sht15_data *data)
+{
+	int err;
+
+	err = gpio_direction_output(data->pdata->gpio_data, 0);
+	if (err)
+		return err;
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_data, 1);
+
+	return 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 int sht15_end_transmission(struct sht15_data *data)
+{
+	int err;
+
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
+	ndelay(SHT15_TSU);
+	gpio_set_value(data->pdata->gpio_sck, 1);
+	ndelay(SHT15_TSCKH);
+	gpio_set_value(data->pdata->gpio_sck, 0);
+	ndelay(SHT15_TSCKL);
+	return 0;
+}
+
+/**
+ * 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 err;
+
+	err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+	if (err)
+		return err;
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
+	ndelay(SHT15_TSU);
+	sht15_send_byte(data, status);
+	err = sht15_wait_for_response(data);
+	if (err)
+		return err;
+
+	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 unlock;
+		status = sht15_read_byte(data);
+
+		if (data->checksumming) {
+			sht15_ack(data);
+			dev_checksum = bitrev8(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);
+		}
+
+		ret = sht15_end_transmission(data);
+		if (ret)
+			goto unlock;
+
+		/*
+		 * 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 unlock;
+			if (previous_config) {
+				ret = sht15_send_status(data, previous_config);
+				if (ret) {
+					dev_err(data->dev,
+						"CRC validation failed, unable "
+						"to restore device settings\n");
+					goto unlock;
+				}
+			}
+			ret = -EAGAIN;
+			goto unlock;
+		}
+
+		data->val_status = status;
+		data->status_valid = true;
+		data->last_status = jiffies;
+	}
+
+unlock:
+	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 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;
+
+	ret = gpio_direction_input(data->pdata->gpio_data);
+	if (ret)
+		return ret;
+	atomic_set(&data->interrupt_handled, 0);
+
+	enable_irq(gpio_to_irq(data->pdata->gpio_data));
+	if (gpio_get_value(data->pdata->gpio_data) == 0) {
+		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+		/* Only relevant if the interrupt hasn't occurred. */
+		if (!atomic_read(&data->interrupt_handled))
+			schedule_work(&data->read_work);
+	}
+	ret = wait_event_timeout(data->wait_queue,
+				 (data->state == SHT15_READING_NOTHING),
+				 msecs_to_jiffies(timeout_msecs));
+	if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */
+		data->state = SHT15_READING_NOTHING;
+		return -EIO;
+	} else if (ret == 0) { /* timeout occurred */
+		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+		ret = sht15_connection_reset(data);
+		if (ret)
+			return ret;
+		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_measurements() - get updated measures from device if too old
+ * @data:	device state
+ */
+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_measurement + timeout)
+	    || !data->measurements_valid) {
+		data->state = SHT15_READING_HUMID;
+		ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
+		if (ret)
+			goto unlock;
+		data->state = SHT15_READING_TEMP;
+		ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
+		if (ret)
+			goto unlock;
+		data->measurements_valid = true;
+		data->last_measurement = jiffies;
+	}
+
+unlock:
+	mutex_unlock(&data->read_lock);
+	return ret;
+}
+
+/**
+ * sht15_calc_temp() - convert the raw reading to a temperature
+ * @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--)
+		/* Find pointer to interpolate */
+		if (data->supply_uv > temppoints[i - 1].vdd) {
+			d1 = (data->supply_uv - temppoints[i - 1].vdd)
+				* (temppoints[i].d1 - temppoints[i - 1].d1)
+				/ (temppoints[i].vdd - temppoints[i - 1].vdd)
+				+ temppoints[i - 1].d1;
+			break;
+		}
+
+	return data->val_temp * d2 + d1;
+}
+
+/**
+ * sht15_calc_humid() - using last temperature convert raw to humid
+ * @data:	device state
+ *
+ * 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 rh_linear; /* milli percent */
+	int temp = sht15_calc_temp(data);
+	int c2, c3;
+	int t2;
+	const int c1 = -4;
+
+	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 + 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 write 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 (kstrtol(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)
+{
+	int ret;
+	struct sht15_data *data = dev_get_drvdata(dev);
+
+	/* Technically no need to read humidity as well */
+	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)
+{
+	int ret;
+	struct sht15_data *data = dev_get_drvdata(dev);
+
+	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)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	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_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,
+};
+
+static const struct attribute_group sht15_attr_group = {
+	.attrs = sht15_attrs,
+};
+
+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->state != SHT15_READING_NOTHING)
+		schedule_work(&data->read_work);
+	return IRQ_HANDLED;
+}
+
+static void sht15_bh_read_data(struct work_struct *work_s)
+{
+	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!
+		 */
+		atomic_set(&data->interrupt_handled, 0);
+		enable_irq(gpio_to_irq(data->pdata->gpio_data));
+		/* If still not occurred or another handler was scheduled */
+		if (gpio_get_value(data->pdata->gpio_data)
+		    || atomic_read(&data->interrupt_handled))
+			return;
+	}
+
+	/* Read the data back from the device */
+	val = sht15_read_byte(data);
+	val <<= 8;
+	if (sht15_ack(data))
+		goto wakeup;
+	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.
+		 */
+		if (sht15_ack(data))
+			goto wakeup;
+		dev_checksum = bitrev8(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 */
+	if (sht15_end_transmission(data))
+		goto wakeup;
+
+	switch (data->state) {
+	case SHT15_READING_TEMP:
+		data->val_temp = val;
+		break;
+	case SHT15_READING_HUMID:
+		data->val_humid = val;
+		break;
+	default:
+		break;
+	}
+
+	data->state = SHT15_READING_NOTHING;
+wakeup:
+	wake_up(&data->wait_queue);
+}
+
+static void sht15_update_voltage(struct work_struct *work_s)
+{
+	struct sht15_data *data
+		= container_of(work_s, struct sht15_data,
+			       update_supply_work);
+	data->supply_uv = regulator_get_voltage(data->reg);
+}
+
+/**
+ * sht15_invalidate_voltage() - mark supply voltage invalid when notified by reg
+ * @nb:		associated notification structure
+ * @event:	voltage regulator state change event code
+ * @ignored:	function parameter - ignored here
+ *
+ * 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)
+{
+	struct sht15_data *data = container_of(nb, struct sht15_data, nb);
+
+	if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
+		data->supply_uv_valid = false;
+	schedule_work(&data->update_supply_work);
+
+	return NOTIFY_OK;
+}
+
+static int sht15_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sht15_data *data;
+	u8 status = 0;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	INIT_WORK(&data->read_work, sht15_bh_read_data);
+	INIT_WORK(&data->update_supply_work, sht15_update_voltage);
+	platform_set_drvdata(pdev, data);
+	mutex_init(&data->read_lock);
+	data->dev = &pdev->dev;
+	init_waitqueue_head(&data->wait_queue);
+
+	if (dev_get_platdata(&pdev->dev) == NULL) {
+		dev_err(&pdev->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+	data->pdata = dev_get_platdata(&pdev->dev);
+	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!
+	 */
+	data->reg = devm_regulator_get_optional(data->dev, "vcc");
+	if (!IS_ERR(data->reg)) {
+		int voltage;
+
+		voltage = regulator_get_voltage(data->reg);
+		if (voltage)
+			data->supply_uv = voltage;
+
+		ret = regulator_enable(data->reg);
+		if (ret != 0) {
+			dev_err(&pdev->dev,
+				"failed to enable regulator: %d\n", ret);
+			return ret;
+		}
+
+		/*
+		 * 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);
+			return ret;
+		}
+	}
+
+	/* Try requesting the GPIOs */
+	ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
+			GPIOF_OUT_INIT_LOW, "SHT15 sck");
+	if (ret) {
+		dev_err(&pdev->dev, "clock line GPIO request failed\n");
+		goto err_release_reg;
+	}
+
+	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
+				"SHT15 data");
+	if (ret) {
+		dev_err(&pdev->dev, "data line GPIO request failed\n");
+		goto err_release_reg;
+	}
+
+	ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+			       sht15_interrupt_fired,
+			       IRQF_TRIGGER_FALLING,
+			       "sht15 data",
+			       data);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to get irq for data line\n");
+		goto err_release_reg;
+	}
+	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+	ret = sht15_connection_reset(data);
+	if (ret)
+		goto err_release_reg;
+	ret = sht15_soft_reset(data);
+	if (ret)
+		goto err_release_reg;
+
+	/* write status with platform data options */
+	if (status) {
+		ret = sht15_send_status(data, status);
+		if (ret)
+			goto err_release_reg;
+	}
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
+	if (ret) {
+		dev_err(&pdev->dev, "sysfs create failed\n");
+		goto err_release_reg;
+	}
+
+	data->hwmon_dev = hwmon_device_register(data->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto err_release_sysfs_group;
+	}
+
+	return 0;
+
+err_release_sysfs_group:
+	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
+err_release_reg:
+	if (!IS_ERR(data->reg)) {
+		regulator_unregister_notifier(data->reg, &data->nb);
+		regulator_disable(data->reg);
+	}
+	return ret;
+}
+
+static int sht15_remove(struct platform_device *pdev)
+{
+	struct sht15_data *data = platform_get_drvdata(pdev);
+
+	/*
+	 * 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)) {
+		regulator_unregister_notifier(data->reg, &data->nb);
+		regulator_disable(data->reg);
+	}
+
+	mutex_unlock(&data->read_lock);
+
+	return 0;
+}
+
+static const struct platform_device_id sht15_device_ids[] = {
+	{ "sht10", sht10 },
+	{ "sht11", sht11 },
+	{ "sht15", sht15 },
+	{ "sht71", sht71 },
+	{ "sht75", sht75 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, sht15_device_ids);
+
+static struct platform_driver sht15_driver = {
+	.driver = {
+		.name = "sht15",
+	},
+	.probe = sht15_probe,
+	.remove = sht15_remove,
+	.id_table = sht15_device_ids,
+};
+module_platform_driver(sht15_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver");
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
new file mode 100644
index 0000000..84cdb1c
--- /dev/null
+++ b/drivers/hwmon/sht21.c
@@ -0,0 +1,226 @@
+/* Sensirion SHT21 humidity and temperature sensor driver
+ *
+ * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
+ *
+ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Data sheet available (5/2010) at
+ * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+
+/* I2C command bytes */
+#define SHT21_TRIG_T_MEASUREMENT_HM  0xe3
+#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
+
+/**
+ * struct sht21 - SHT21 device specific data
+ * @hwmon_dev: device registered with hwmon
+ * @lock: mutex to protect measurement values
+ * @valid: only 0 before first measurement is taken
+ * @last_update: time of last update (jiffies)
+ * @temperature: cached temperature measurement value
+ * @humidity: cached humidity measurement value
+ */
+struct sht21 {
+	struct i2c_client *client;
+	struct mutex lock;
+	char valid;
+	unsigned long last_update;
+	int temperature;
+	int humidity;
+};
+
+/**
+ * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to
+ * milli celsius
+ * @ticks: temperature ticks value received from sensor
+ */
+static inline int sht21_temp_ticks_to_millicelsius(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((21965 * ticks) >> 13) - 46850;
+}
+
+/**
+ * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
+ * one-thousandths of a percent relative humidity
+ * @ticks: humidity ticks value received from sensor
+ */
+static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((15625 * ticks) >> 13) - 6000;
+}
+
+/**
+ * sht21_update_measurements() - get updated measurements from device
+ * @dev: device
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int sht21_update_measurements(struct device *dev)
+{
+	int ret = 0;
+	struct sht21 *sht21 = dev_get_drvdata(dev);
+	struct i2c_client *client = sht21->client;
+
+	mutex_lock(&sht21->lock);
+	/*
+	 * Data sheet 2.4:
+	 * SHT2x should not be active for more than 10% of the time - e.g.
+	 * maximum two measurements per second at 12bit accuracy shall be made.
+	 */
+	if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) {
+		ret = i2c_smbus_read_word_swapped(client,
+						  SHT21_TRIG_T_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		sht21->temperature = sht21_temp_ticks_to_millicelsius(ret);
+		ret = i2c_smbus_read_word_swapped(client,
+						  SHT21_TRIG_RH_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret);
+		sht21->last_update = jiffies;
+		sht21->valid = 1;
+	}
+out:
+	mutex_unlock(&sht21->lock);
+
+	return ret >= 0 ? 0 : ret;
+}
+
+/**
+ * sht21_show_temperature() - show temperature measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) 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 sht21_show_temperature(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	struct sht21 *sht21 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = sht21_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", sht21->temperature);
+}
+
+/**
+ * sht21_show_humidity() - show humidity measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) 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 sht21_show_humidity(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	struct sht21 *sht21 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = sht21_update_measurements(dev);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", sht21->humidity);
+}
+
+/* sysfs attributes */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
+	NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
+	NULL, 0);
+
+static struct attribute *sht21_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(sht21);
+
+static int sht21_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct sht21 *sht21;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(&client->dev,
+			"adapter does not support SMBus word transactions\n");
+		return -ENODEV;
+	}
+
+	sht21 = devm_kzalloc(dev, sizeof(*sht21), GFP_KERNEL);
+	if (!sht21)
+		return -ENOMEM;
+
+	sht21->client = client;
+
+	mutex_init(&sht21->lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   sht21, sht21_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* Device ID table */
+static const struct i2c_device_id sht21_id[] = {
+	{ "sht21", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sht21_id);
+
+static struct i2c_driver sht21_driver = {
+	.driver.name = "sht21",
+	.probe       = sht21_probe,
+	.id_table    = sht21_id,
+};
+
+module_i2c_driver(sht21_driver);
+
+MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>");
+MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c
new file mode 100644
index 0000000..decd7df
--- /dev/null
+++ b/drivers/hwmon/shtc1.c
@@ -0,0 +1,251 @@
+/* Sensirion SHTC1 humidity and temperature sensor driver
+ *
+ * Copyright (C) 2014 Sensirion AG, Switzerland
+ * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_data/shtc1.h>
+
+/* commands (high precision mode) */
+static const unsigned char shtc1_cmd_measure_blocking_hpm[]    = { 0x7C, 0xA2 };
+static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 };
+
+/* commands (low precision mode) */
+static const unsigned char shtc1_cmd_measure_blocking_lpm[]    = { 0x64, 0x58 };
+static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
+
+/* command for reading the ID register */
+static const unsigned char shtc1_cmd_read_id_reg[]	       = { 0xef, 0xc8 };
+
+/* constants for reading the ID register */
+#define SHTC1_ID	  0x07
+#define SHTC1_ID_REG_MASK 0x1f
+
+/* delays for non-blocking i2c commands, both in us */
+#define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
+#define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
+
+#define SHTC1_CMD_LENGTH      2
+#define SHTC1_RESPONSE_LENGTH 6
+
+struct shtc1_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated; /* in jiffies */
+
+	const unsigned char *command;
+	unsigned int nonblocking_wait_time; /* in us */
+
+	struct shtc1_platform_data setup;
+
+	int temperature; /* 1000 * temperature in dgr C */
+	int humidity; /* 1000 * relative humidity in %RH */
+};
+
+static int shtc1_update_values(struct i2c_client *client,
+			       struct shtc1_data *data,
+			       char *buf, int bufsize)
+{
+	int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH);
+	if (ret != SHTC1_CMD_LENGTH) {
+		dev_err(&client->dev, "failed to send command: %d\n", ret);
+		return ret < 0 ? ret : -EIO;
+	}
+
+	/*
+	 * In blocking mode (clock stretching mode) the I2C bus
+	 * is blocked for other traffic, thus the call to i2c_master_recv()
+	 * will wait until the data is ready. For non blocking mode, we
+	 * have to wait ourselves.
+	 */
+	if (!data->setup.blocking_io)
+		usleep_range(data->nonblocking_wait_time,
+			     data->nonblocking_wait_time + 1000);
+
+	ret = i2c_master_recv(client, buf, bufsize);
+	if (ret != bufsize) {
+		dev_err(&client->dev, "failed to read values: %d\n", ret);
+		return ret < 0 ? ret : -EIO;
+	}
+
+	return 0;
+}
+
+/* sysfs attributes */
+static struct shtc1_data *shtc1_update_client(struct device *dev)
+{
+	struct shtc1_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned char buf[SHTC1_RESPONSE_LENGTH];
+	int val;
+	int ret = 0;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
+		ret = shtc1_update_values(client, data, buf, sizeof(buf));
+		if (ret)
+			goto out;
+
+		/*
+		 * From datasheet:
+		 * T = -45 + 175 * ST / 2^16
+		 * RH = 100 * SRH / 2^16
+		 *
+		 * Adapted for integer fixed point (3 digit) arithmetic.
+		 */
+		val = be16_to_cpup((__be16 *)buf);
+		data->temperature = ((21875 * val) >> 13) - 45000;
+		val = be16_to_cpup((__be16 *)(buf + 3));
+		data->humidity = ((12500 * val) >> 13);
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+out:
+	mutex_unlock(&data->update_lock);
+
+	return ret == 0 ? data : ERR_PTR(ret);
+}
+
+static ssize_t temp1_input_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct shtc1_data *data = shtc1_update_client(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->temperature);
+}
+
+static ssize_t humidity1_input_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct shtc1_data *data = shtc1_update_client(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", data->humidity);
+}
+
+static DEVICE_ATTR_RO(temp1_input);
+static DEVICE_ATTR_RO(humidity1_input);
+
+static struct attribute *shtc1_attrs[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_humidity1_input.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(shtc1);
+
+static void shtc1_select_command(struct shtc1_data *data)
+{
+	if (data->setup.high_precision) {
+		data->command = data->setup.blocking_io ?
+				shtc1_cmd_measure_blocking_hpm :
+				shtc1_cmd_measure_nonblocking_hpm;
+		data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM;
+
+	} else {
+		data->command = data->setup.blocking_io ?
+				shtc1_cmd_measure_blocking_lpm :
+				shtc1_cmd_measure_nonblocking_lpm;
+		data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM;
+	}
+}
+
+static int shtc1_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	int ret;
+	char id_reg[2];
+	struct shtc1_data *data;
+	struct device *hwmon_dev;
+	struct i2c_adapter *adap = client->adapter;
+	struct device *dev = &client->dev;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) {
+		dev_err(dev, "plain i2c transactions not supported\n");
+		return -ENODEV;
+	}
+
+	ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH);
+	if (ret != SHTC1_CMD_LENGTH) {
+		dev_err(dev, "could not send read_id_reg command: %d\n", ret);
+		return ret < 0 ? ret : -ENODEV;
+	}
+	ret = i2c_master_recv(client, id_reg, sizeof(id_reg));
+	if (ret != sizeof(id_reg)) {
+		dev_err(dev, "could not read ID register: %d\n", ret);
+		return -ENODEV;
+	}
+	if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) {
+		dev_err(dev, "ID register doesn't match\n");
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->setup.blocking_io = false;
+	data->setup.high_precision = true;
+	data->client = client;
+
+	if (client->dev.platform_data)
+		data->setup = *(struct shtc1_platform_data *)dev->platform_data;
+	shtc1_select_command(data);
+	mutex_init(&data->update_lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   client->name,
+							   data,
+							   shtc1_groups);
+	if (IS_ERR(hwmon_dev))
+		dev_dbg(dev, "unable to register hwmon device\n");
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/* device ID table */
+static const struct i2c_device_id shtc1_id[] = {
+	{ "shtc1", 0 },
+	{ "shtw1", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, shtc1_id);
+
+static struct i2c_driver shtc1_i2c_driver = {
+	.driver.name  = "shtc1",
+	.probe        = shtc1_probe,
+	.id_table     = shtc1_id,
+};
+
+module_i2c_driver(shtc1_i2c_driver);
+
+MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>");
+MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
new file mode 100644
index 0000000..45a028f
--- /dev/null
+++ b/drivers/hwmon/sis5595.c
@@ -0,0 +1,932 @@
+/*
+ * sis5595.c - Part of lm_sensors, Linux kernel modules
+ *	       for hardware monitoring
+ *
+ * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
+ *			     Kyösti Mälkki <kmalkki@cc.hut.fi>, and
+ *			     Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
+ * the help of Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+/*
+ * SiS southbridge has a LM78-like chip integrated on the same IC.
+ * This driver is a customized copy of lm78.c
+ *
+ * Supports following revisions:
+ *	Version		PCI ID		PCI Revision
+ *	1		1039/0008	AF or less
+ *	2		1039/0008	B0 or greater
+ *
+ *  Note: these chips contain a 0008 device which is incompatible with the
+ *	 5595. We recognize these by the presence of the listed
+ *	 "blacklist" PCI ID and refuse to load.
+ *
+ * NOT SUPPORTED	PCI ID		BLACKLIST PCI ID
+ *	 540		0008		0540
+ *	 550		0008		0550
+ *	5513		0008		5511
+ *	5581		0008		5597
+ *	5582		0008		5597
+ *	5597		0008		5597
+ *	5598		0008		5597/5598
+ *	 630		0008		0630
+ *	 645		0008		0645
+ *	 730		0008		0730
+ *	 735		0008		0735
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/*
+ * If force_addr is set to anything different from 0, we forcibly enable
+ * the device at the given address.
+ */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+
+static struct platform_device *pdev;
+
+/* Many SIS5595 constants specified below */
+
+/* Length of ISA address segment */
+#define SIS5595_EXTENT 8
+/* PCI Config Registers */
+#define SIS5595_BASE_REG 0x68
+#define SIS5595_PIN_REG 0x7A
+#define SIS5595_ENABLE_REG 0x7B
+
+/* Where are the ISA address/data registers relative to the base address */
+#define SIS5595_ADDR_REG_OFFSET 5
+#define SIS5595_DATA_REG_OFFSET 6
+
+/* The SIS5595 registers */
+#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
+#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
+#define SIS5595_REG_IN(nr) (0x20 + (nr))
+
+#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
+#define SIS5595_REG_FAN(nr) (0x28 + (nr))
+
+/*
+ * On the first version of the chip, the temp registers are separate.
+ * On the second version,
+ * TEMP pin is shared with IN4, configured in PCI register 0x7A.
+ * The registers are the same as well.
+ * OVER and HYST are really MAX and MIN.
+ */
+
+#define REV2MIN	0xb0
+#define SIS5595_REG_TEMP	(((data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN(4) : 0x27)
+#define SIS5595_REG_TEMP_OVER	(((data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN_MAX(4) : 0x39)
+#define SIS5595_REG_TEMP_HYST	(((data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN_MIN(4) : 0x3a)
+
+#define SIS5595_REG_CONFIG 0x40
+#define SIS5595_REG_ALARM1 0x41
+#define SIS5595_REG_ALARM2 0x42
+#define SIS5595_REG_FANDIV 0x47
+
+/*
+ * Conversions. Limit checking is only done on the TO_REG
+ * variants.
+ */
+
+/*
+ * IN: mV, (0V to 4.08V)
+ * REG: 16mV/bit
+ */
+static inline u8 IN_TO_REG(unsigned long val)
+{
+	unsigned long nval = clamp_val(val, 0, 4080);
+	return (nval + 8) / 16;
+}
+#define IN_FROM_REG(val) ((val) *  16)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm <= 0)
+		return 255;
+	if (rpm > 1350000)
+		return 1;
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static inline int FAN_FROM_REG(u8 val, int div)
+{
+	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
+}
+
+/*
+ * TEMP: mC (-54.12C to +157.53C)
+ * REG: 0.83C/bit + 52.12, two's complement
+ */
+static inline int TEMP_FROM_REG(s8 val)
+{
+	return val * 830 + 52120;
+}
+static inline s8 TEMP_TO_REG(long val)
+{
+	int nval = clamp_val(val, -54120, 157530) ;
+	return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
+}
+
+/*
+ * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
+ * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
+ */
+static inline u8 DIV_TO_REG(int val)
+{
+	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
+}
+#define DIV_FROM_REG(val) (1 << (val))
+
+/*
+ * For each registered chip, we need to keep some data in memory.
+ * The structure is dynamically allocated.
+ */
+struct sis5595_data {
+	unsigned short addr;
+	const char *name;
+	struct device *hwmon_dev;
+	struct mutex lock;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
+	u8 revision;		/* Reg. value */
+
+	u8 in[5];		/* Register value */
+	u8 in_max[5];		/* Register value */
+	u8 in_min[5];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_over;		/* Register value */
+	s8 temp_hyst;		/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
+
+static int sis5595_probe(struct platform_device *pdev);
+static int sis5595_remove(struct platform_device *pdev);
+
+static int sis5595_read_value(struct sis5595_data *data, u8 reg);
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
+static struct sis5595_data *sis5595_update_device(struct device *dev);
+static void sis5595_init_device(struct sis5595_data *data);
+
+static struct platform_driver sis5595_driver = {
+	.driver = {
+		.name	= "sis5595",
+	},
+	.probe		= sis5595_probe,
+	.remove		= sis5595_remove,
+};
+
+/* 4 Voltages */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		       char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+			   char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val);
+	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val);
+	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_in_offset(offset)					\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
+
+show_in_offset(0);
+show_in_offset(1);
+show_in_offset(2);
+show_in_offset(3);
+show_in_offset(4);
+
+/* Temperature */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
+}
+
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
+}
+
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_over = TEMP_TO_REG(val);
+	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
+}
+
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_hyst = TEMP_TO_REG(val);
+	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		show_temp_over, set_temp_over);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		show_temp_hyst, set_temp_hyst);
+
+/* 2 Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+			char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+		DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+			    char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long min;
+	int reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			DIV_FROM_REG(data->fan_div[nr]));
+	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
+
+	switch (val) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		dev_err(dev,
+			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+			val);
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	switch (nr) {
+	case 0:
+		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
+		break;
+	case 1:
+		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
+		break;
+	}
+	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
+	data->fan_min[nr] =
+		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_fan_offset(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);
+
+show_fan_offset(1);
+show_fan_offset(2);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	int nr = to_sensor_dev_attr(da)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *sis5595_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group sis5595_group = {
+	.attrs = sis5595_attributes,
+};
+
+static struct attribute *sis5595_attributes_in4[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group sis5595_group_in4 = {
+	.attrs = sis5595_attributes_in4,
+};
+
+static struct attribute *sis5595_attributes_temp1[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_max_hyst.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group sis5595_group_temp1 = {
+	.attrs = sis5595_attributes_temp1,
+};
+
+/* This is called when the module is loaded */
+static int sis5595_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	int i;
+	struct sis5595_data *data;
+	struct resource *res;
+	char val;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT,
+				 sis5595_driver.driver.name))
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+	data->addr = res->start;
+	data->name = "sis5595";
+	platform_set_drvdata(pdev, data);
+
+	/*
+	 * Check revision and pin registers to determine whether 4 or 5 voltages
+	 */
+	data->revision = s_bridge->revision;
+	/* 4 voltages, 1 temp */
+	data->maxins = 3;
+	if (data->revision >= REV2MIN) {
+		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
+		if (!(val & 0x80))
+			/* 5 voltages, no temps */
+			data->maxins = 4;
+	}
+
+	/* Initialize the SIS5595 chip */
+	sis5595_init_device(data);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 2; i++) {
+		data->fan_min[i] = sis5595_read_value(data,
+					SIS5595_REG_FAN_MIN(i));
+	}
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group);
+	if (err)
+		return err;
+	if (data->maxins == 4) {
+		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4);
+		if (err)
+			goto exit_remove_files;
+	} else {
+		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->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(&pdev->dev.kobj, &sis5595_group);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
+	return err;
+}
+
+static int sis5595_remove(struct platform_device *pdev)
+{
+	struct sis5595_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
+
+	return 0;
+}
+
+
+/* ISA access must be locked explicitly. */
+static int sis5595_read_value(struct sis5595_data *data, u8 reg)
+{
+	int res;
+
+	mutex_lock(&data->lock);
+	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
+	mutex_unlock(&data->lock);
+	return res;
+}
+
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
+{
+	mutex_lock(&data->lock);
+	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
+	mutex_unlock(&data->lock);
+}
+
+/* Called when we have found a new SIS5595. */
+static void sis5595_init_device(struct sis5595_data *data)
+{
+	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
+	if (!(config & 0x01))
+		sis5595_write_value(data, SIS5595_REG_CONFIG,
+				(config & 0xf7) | 0x01);
+}
+
+static struct sis5595_data *sis5595_update_device(struct device *dev)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+
+		for (i = 0; i <= data->maxins; i++) {
+			data->in[i] =
+			    sis5595_read_value(data, SIS5595_REG_IN(i));
+			data->in_min[i] =
+			    sis5595_read_value(data,
+					       SIS5595_REG_IN_MIN(i));
+			data->in_max[i] =
+			    sis5595_read_value(data,
+					       SIS5595_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 2; i++) {
+			data->fan[i] =
+			    sis5595_read_value(data, SIS5595_REG_FAN(i));
+			data->fan_min[i] =
+			    sis5595_read_value(data,
+					       SIS5595_REG_FAN_MIN(i));
+		}
+		if (data->maxins == 3) {
+			data->temp =
+			    sis5595_read_value(data, SIS5595_REG_TEMP);
+			data->temp_over =
+			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
+			data->temp_hyst =
+			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
+		}
+		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = i >> 6;
+		data->alarms =
+		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
+		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static const struct pci_device_id sis5595_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
+
+static int blacklist[] = {
+	PCI_DEVICE_ID_SI_540,
+	PCI_DEVICE_ID_SI_550,
+	PCI_DEVICE_ID_SI_630,
+	PCI_DEVICE_ID_SI_645,
+	PCI_DEVICE_ID_SI_730,
+	PCI_DEVICE_ID_SI_735,
+	PCI_DEVICE_ID_SI_5511, /*
+				* 5513 chip has the 0008 device but
+				* that ID shows up in other chips so we
+				* use the 5511 ID for recognition
+				*/
+	PCI_DEVICE_ID_SI_5597,
+	PCI_DEVICE_ID_SI_5598,
+	0 };
+
+static int sis5595_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SIS5595_EXTENT - 1,
+		.name	= "sis5595",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc("sis5595", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int sis5595_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	u16 address;
+	u8 enable;
+	int *i;
+
+	for (i = blacklist; *i != 0; i++) {
+		struct pci_dev *d;
+		d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
+		if (d) {
+			dev_err(&d->dev,
+				"Looked for SIS5595 but found unsupported device %.4x\n",
+				*i);
+			pci_dev_put(d);
+			return -ENODEV;
+		}
+	}
+
+	force_addr &= ~(SIS5595_EXTENT - 1);
+	if (force_addr) {
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
+		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
+	}
+
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+		dev_err(&dev->dev, "Failed to read ISA address\n");
+		return -ENODEV;
+	}
+
+	address &= ~(SIS5595_EXTENT - 1);
+	if (!address) {
+		dev_err(&dev->dev,
+			"Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+	if (force_addr && address != force_addr) {
+		/* doesn't work for some chips? */
+		dev_err(&dev->dev, "Failed to force ISA address\n");
+		return -ENODEV;
+	}
+
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+		dev_err(&dev->dev, "Failed to read enable register\n");
+		return -ENODEV;
+	}
+	if (!(enable & 0x80)) {
+		if ((PCIBIOS_SUCCESSFUL !=
+		     pci_write_config_byte(dev, SIS5595_ENABLE_REG,
+					   enable | 0x80))
+		 || (PCIBIOS_SUCCESSFUL !=
+		     pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
+		 || (!(enable & 0x80))) {
+			/* doesn't work for some chips! */
+			dev_err(&dev->dev, "Failed to enable HWM device\n");
+			return -ENODEV;
+		}
+	}
+
+	if (platform_driver_register(&sis5595_driver)) {
+		dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
+		goto exit;
+	}
+
+	s_bridge = pci_dev_get(dev);
+	/* Sets global pdev as a side effect */
+	if (sis5595_device_add(address))
+		goto exit_unregister;
+
+	/*
+	 * Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+	return -ENODEV;
+
+exit_unregister:
+	pci_dev_put(dev);
+	platform_driver_unregister(&sis5595_driver);
+exit:
+	return -ENODEV;
+}
+
+static struct pci_driver sis5595_pci_driver = {
+	.name            = "sis5595",
+	.id_table        = sis5595_pci_ids,
+	.probe           = sis5595_pci_probe,
+};
+
+static int __init sm_sis5595_init(void)
+{
+	return pci_register_driver(&sis5595_pci_driver);
+}
+
+static void __exit sm_sis5595_exit(void)
+{
+	pci_unregister_driver(&sis5595_pci_driver);
+	if (s_bridge != NULL) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&sis5595_driver);
+		pci_dev_put(s_bridge);
+		s_bridge = NULL;
+	}
+}
+
+MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
+MODULE_DESCRIPTION("SiS 5595 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(sm_sis5595_init);
+module_exit(sm_sis5595_exit);
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
new file mode 100644
index 0000000..627c9c3
--- /dev/null
+++ b/drivers/hwmon/smm665.c
@@ -0,0 +1,709 @@
+/*
+ * Driver for SMM665 Power Controller / Monitor
+ *
+ * Copyright (C) 2010 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.
+ *
+ * This driver should also work for SMM465, SMM764, and SMM766, but is untested
+ * for those chips. Only monitoring functionality is implemented.
+ *
+ * Datasheets:
+ * http://www.summitmicro.com/prod_select/summary/SMM665/SMM665B_2089_20.pdf
+ * http://www.summitmicro.com/prod_select/summary/SMM766B/SMM766B_2122.pdf
+ */
+
+#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>
+
+/* Internal reference voltage (VREF, x 1000 */
+#define SMM665_VREF_ADC_X1000	1250
+
+/* module parameters */
+static int vref = SMM665_VREF_ADC_X1000;
+module_param(vref, int, 0);
+MODULE_PARM_DESC(vref, "Reference voltage in mV");
+
+enum chips { smm465, smm665, smm665c, smm764, smm766 };
+
+/*
+ * ADC channel addresses
+ */
+#define	SMM665_MISC16_ADC_DATA_A	0x00
+#define	SMM665_MISC16_ADC_DATA_B	0x01
+#define	SMM665_MISC16_ADC_DATA_C	0x02
+#define	SMM665_MISC16_ADC_DATA_D	0x03
+#define	SMM665_MISC16_ADC_DATA_E	0x04
+#define	SMM665_MISC16_ADC_DATA_F	0x05
+#define	SMM665_MISC16_ADC_DATA_VDD	0x06
+#define	SMM665_MISC16_ADC_DATA_12V	0x07
+#define	SMM665_MISC16_ADC_DATA_INT_TEMP	0x08
+#define	SMM665_MISC16_ADC_DATA_AIN1	0x09
+#define	SMM665_MISC16_ADC_DATA_AIN2	0x0a
+
+/*
+ * Command registers
+ */
+#define	SMM665_MISC8_CMD_STS		0x80
+#define	SMM665_MISC8_STATUS1		0x81
+#define	SMM665_MISC8_STATUSS2		0x82
+#define	SMM665_MISC8_IO_POLARITY	0x83
+#define	SMM665_MISC8_PUP_POLARITY	0x84
+#define	SMM665_MISC8_ADOC_STATUS1	0x85
+#define	SMM665_MISC8_ADOC_STATUS2	0x86
+#define	SMM665_MISC8_WRITE_PROT		0x87
+#define	SMM665_MISC8_STS_TRACK		0x88
+
+/*
+ * Configuration registers and register groups
+ */
+#define SMM665_ADOC_ENABLE		0x0d
+#define SMM665_LIMIT_BASE		0x80	/* First limit register */
+
+/*
+ * Limit register bit masks
+ */
+#define SMM665_TRIGGER_RST		0x8000
+#define SMM665_TRIGGER_HEALTHY		0x4000
+#define SMM665_TRIGGER_POWEROFF		0x2000
+#define SMM665_TRIGGER_SHUTDOWN		0x1000
+#define SMM665_ADC_MASK			0x03ff
+
+#define smm665_is_critical(lim)	((lim) & (SMM665_TRIGGER_RST \
+					| SMM665_TRIGGER_POWEROFF \
+					| SMM665_TRIGGER_SHUTDOWN))
+/*
+ * Fault register bit definitions
+ * Values are merged from status registers 1/2,
+ * with status register 1 providing the upper 8 bits.
+ */
+#define SMM665_FAULT_A		0x0001
+#define SMM665_FAULT_B		0x0002
+#define SMM665_FAULT_C		0x0004
+#define SMM665_FAULT_D		0x0008
+#define SMM665_FAULT_E		0x0010
+#define SMM665_FAULT_F		0x0020
+#define SMM665_FAULT_VDD	0x0040
+#define SMM665_FAULT_12V	0x0080
+#define SMM665_FAULT_TEMP	0x0100
+#define SMM665_FAULT_AIN1	0x0200
+#define SMM665_FAULT_AIN2	0x0400
+
+/*
+ * I2C Register addresses
+ *
+ * The configuration register needs to be the configured base register.
+ * The command/status register address is derived from it.
+ */
+#define SMM665_REGMASK		0x78
+#define SMM665_CMDREG_BASE	0x48
+#define SMM665_CONFREG_BASE	0x50
+
+/*
+ *  Equations given by chip manufacturer to calculate voltage/temperature values
+ *  vref = Reference voltage on VREF_ADC pin (module parameter)
+ *  adc  = 10bit ADC value read back from registers
+ */
+
+/* Voltage A-F and VDD */
+#define SMM665_VMON_ADC_TO_VOLTS(adc)  ((adc) * vref / 256)
+
+/* Voltage 12VIN */
+#define SMM665_12VIN_ADC_TO_VOLTS(adc) ((adc) * vref * 3 / 256)
+
+/* Voltage AIN1, AIN2 */
+#define SMM665_AIN_ADC_TO_VOLTS(adc)   ((adc) * vref / 512)
+
+/* Temp Sensor */
+#define SMM665_TEMP_ADC_TO_CELSIUS(adc) (((adc) <= 511) ?		   \
+					 ((int)(adc) * 1000 / 4) :	   \
+					 (((int)(adc) - 0x400) * 1000 / 4))
+
+#define SMM665_NUM_ADC		11
+
+/*
+ * Chip dependent ADC conversion time, in uS
+ */
+#define SMM665_ADC_WAIT_SMM665	70
+#define SMM665_ADC_WAIT_SMM766	185
+
+struct smm665_data {
+	enum chips type;
+	int conversion_time;		/* ADC conversion time */
+	struct i2c_client *client;
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+	u16 adc[SMM665_NUM_ADC];	/* adc values (raw) */
+	u16 faults;			/* fault status */
+	/* The following values are in mV */
+	int critical_min_limit[SMM665_NUM_ADC];
+	int alarm_min_limit[SMM665_NUM_ADC];
+	int critical_max_limit[SMM665_NUM_ADC];
+	int alarm_max_limit[SMM665_NUM_ADC];
+	struct i2c_client *cmdreg;
+};
+
+/*
+ * smm665_read16()
+ *
+ * Read 16 bit value from <reg>, <reg+1>. Upper 8 bits are in <reg>.
+ */
+static int smm665_read16(struct i2c_client *client, int reg)
+{
+	int rv, val;
+
+	rv = i2c_smbus_read_byte_data(client, reg);
+	if (rv < 0)
+		return rv;
+	val = rv << 8;
+	rv = i2c_smbus_read_byte_data(client, reg + 1);
+	if (rv < 0)
+		return rv;
+	val |= rv;
+	return val;
+}
+
+/*
+ * Read adc value.
+ */
+static int smm665_read_adc(struct smm665_data *data, int adc)
+{
+	struct i2c_client *client = data->cmdreg;
+	int rv;
+	int radc;
+
+	/*
+	 * Algorithm for reading ADC, per SMM665 datasheet
+	 *
+	 *  {[S][addr][W][Ack]} {[offset][Ack]} {[S][addr][R][Nack]}
+	 * [wait conversion time]
+	 *  {[S][addr][R][Ack]} {[datahi][Ack]} {[datalo][Ack][P]}
+	 *
+	 * To implement the first part of this exchange,
+	 * do a full read transaction and expect a failure/Nack.
+	 * This sets up the address pointer on the SMM665
+	 * and starts the ADC conversion.
+	 * Then do a two-byte read transaction.
+	 */
+	rv = i2c_smbus_read_byte_data(client, adc << 3);
+	if (rv != -ENXIO) {
+		/*
+		 * We expect ENXIO to reflect NACK
+		 * (per Documentation/i2c/fault-codes).
+		 * Everything else is an error.
+		 */
+		dev_dbg(&client->dev,
+			"Unexpected return code %d when setting ADC index", rv);
+		return (rv < 0) ? rv : -EIO;
+	}
+
+	udelay(data->conversion_time);
+
+	/*
+	 * Now read two bytes.
+	 *
+	 * Neither i2c_smbus_read_byte() nor
+	 * i2c_smbus_read_block_data() worked here,
+	 * so use i2c_smbus_read_word_swapped() instead.
+	 * We could also try to use i2c_master_recv(),
+	 * but that is not always supported.
+	 */
+	rv = i2c_smbus_read_word_swapped(client, 0);
+	if (rv < 0) {
+		dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
+		return rv;
+	}
+	/*
+	 * Validate/verify readback adc channel (in bit 11..14).
+	 */
+	radc = (rv >> 11) & 0x0f;
+	if (radc != adc) {
+		dev_dbg(&client->dev, "Unexpected RADC: Expected %d got %d",
+			adc, radc);
+		return -EIO;
+	}
+
+	return rv & SMM665_ADC_MASK;
+}
+
+static struct smm665_data *smm665_update_device(struct device *dev)
+{
+	struct smm665_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct smm665_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		int i, val;
+
+		/*
+		 * read status registers
+		 */
+		val = smm665_read16(client, SMM665_MISC8_STATUS1);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->faults = val;
+
+		/* Read adc registers */
+		for (i = 0; i < SMM665_NUM_ADC; i++) {
+			val = smm665_read_adc(data, i);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->adc[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* Return converted value from given adc */
+static int smm665_convert(u16 adcval, int index)
+{
+	int val = 0;
+
+	switch (index) {
+	case SMM665_MISC16_ADC_DATA_12V:
+		val = SMM665_12VIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
+		break;
+
+	case SMM665_MISC16_ADC_DATA_VDD:
+	case SMM665_MISC16_ADC_DATA_A:
+	case SMM665_MISC16_ADC_DATA_B:
+	case SMM665_MISC16_ADC_DATA_C:
+	case SMM665_MISC16_ADC_DATA_D:
+	case SMM665_MISC16_ADC_DATA_E:
+	case SMM665_MISC16_ADC_DATA_F:
+		val = SMM665_VMON_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
+		break;
+
+	case SMM665_MISC16_ADC_DATA_AIN1:
+	case SMM665_MISC16_ADC_DATA_AIN2:
+		val = SMM665_AIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
+		break;
+
+	case SMM665_MISC16_ADC_DATA_INT_TEMP:
+		val = SMM665_TEMP_ADC_TO_CELSIUS(adcval & SMM665_ADC_MASK);
+		break;
+
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		break;
+	}
+
+	return val;
+}
+
+static int smm665_get_min(struct device *dev, int index)
+{
+	struct smm665_data *data = dev_get_drvdata(dev);
+
+	return data->alarm_min_limit[index];
+}
+
+static int smm665_get_max(struct device *dev, int index)
+{
+	struct smm665_data *data = dev_get_drvdata(dev);
+
+	return data->alarm_max_limit[index];
+}
+
+static int smm665_get_lcrit(struct device *dev, int index)
+{
+	struct smm665_data *data = dev_get_drvdata(dev);
+
+	return data->critical_min_limit[index];
+}
+
+static int smm665_get_crit(struct device *dev, int index)
+{
+	struct smm665_data *data = dev_get_drvdata(dev);
+
+	return data->critical_max_limit[index];
+}
+
+static ssize_t smm665_show_crit_alarm(struct device *dev,
+				      struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct smm665_data *data = smm665_update_device(dev);
+	int val = 0;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	if (data->faults & (1 << attr->index))
+		val = 1;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t smm665_show_input(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct smm665_data *data = smm665_update_device(dev);
+	int adc = attr->index;
+	int val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = smm665_convert(data->adc[adc], adc);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+#define SMM665_SHOW(what) \
+static ssize_t smm665_show_##what(struct device *dev, \
+				    struct device_attribute *da, char *buf) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	const int val = smm665_get_##what(dev, attr->index); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", val); \
+}
+
+SMM665_SHOW(min);
+SMM665_SHOW(max);
+SMM665_SHOW(lcrit);
+SMM665_SHOW(crit);
+
+/*
+ * These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define SMM665_ATTR(name, type, cmd_idx) \
+	static SENSOR_DEVICE_ATTR(name##_##type, S_IRUGO, \
+				  smm665_show_##type, NULL, cmd_idx)
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Input voltages */
+SMM665_ATTR(in1, input, SMM665_MISC16_ADC_DATA_12V);
+SMM665_ATTR(in2, input, SMM665_MISC16_ADC_DATA_VDD);
+SMM665_ATTR(in3, input, SMM665_MISC16_ADC_DATA_A);
+SMM665_ATTR(in4, input, SMM665_MISC16_ADC_DATA_B);
+SMM665_ATTR(in5, input, SMM665_MISC16_ADC_DATA_C);
+SMM665_ATTR(in6, input, SMM665_MISC16_ADC_DATA_D);
+SMM665_ATTR(in7, input, SMM665_MISC16_ADC_DATA_E);
+SMM665_ATTR(in8, input, SMM665_MISC16_ADC_DATA_F);
+SMM665_ATTR(in9, input, SMM665_MISC16_ADC_DATA_AIN1);
+SMM665_ATTR(in10, input, SMM665_MISC16_ADC_DATA_AIN2);
+
+/* Input voltages min */
+SMM665_ATTR(in1, min, SMM665_MISC16_ADC_DATA_12V);
+SMM665_ATTR(in2, min, SMM665_MISC16_ADC_DATA_VDD);
+SMM665_ATTR(in3, min, SMM665_MISC16_ADC_DATA_A);
+SMM665_ATTR(in4, min, SMM665_MISC16_ADC_DATA_B);
+SMM665_ATTR(in5, min, SMM665_MISC16_ADC_DATA_C);
+SMM665_ATTR(in6, min, SMM665_MISC16_ADC_DATA_D);
+SMM665_ATTR(in7, min, SMM665_MISC16_ADC_DATA_E);
+SMM665_ATTR(in8, min, SMM665_MISC16_ADC_DATA_F);
+SMM665_ATTR(in9, min, SMM665_MISC16_ADC_DATA_AIN1);
+SMM665_ATTR(in10, min, SMM665_MISC16_ADC_DATA_AIN2);
+
+/* Input voltages max */
+SMM665_ATTR(in1, max, SMM665_MISC16_ADC_DATA_12V);
+SMM665_ATTR(in2, max, SMM665_MISC16_ADC_DATA_VDD);
+SMM665_ATTR(in3, max, SMM665_MISC16_ADC_DATA_A);
+SMM665_ATTR(in4, max, SMM665_MISC16_ADC_DATA_B);
+SMM665_ATTR(in5, max, SMM665_MISC16_ADC_DATA_C);
+SMM665_ATTR(in6, max, SMM665_MISC16_ADC_DATA_D);
+SMM665_ATTR(in7, max, SMM665_MISC16_ADC_DATA_E);
+SMM665_ATTR(in8, max, SMM665_MISC16_ADC_DATA_F);
+SMM665_ATTR(in9, max, SMM665_MISC16_ADC_DATA_AIN1);
+SMM665_ATTR(in10, max, SMM665_MISC16_ADC_DATA_AIN2);
+
+/* Input voltages lcrit */
+SMM665_ATTR(in1, lcrit, SMM665_MISC16_ADC_DATA_12V);
+SMM665_ATTR(in2, lcrit, SMM665_MISC16_ADC_DATA_VDD);
+SMM665_ATTR(in3, lcrit, SMM665_MISC16_ADC_DATA_A);
+SMM665_ATTR(in4, lcrit, SMM665_MISC16_ADC_DATA_B);
+SMM665_ATTR(in5, lcrit, SMM665_MISC16_ADC_DATA_C);
+SMM665_ATTR(in6, lcrit, SMM665_MISC16_ADC_DATA_D);
+SMM665_ATTR(in7, lcrit, SMM665_MISC16_ADC_DATA_E);
+SMM665_ATTR(in8, lcrit, SMM665_MISC16_ADC_DATA_F);
+SMM665_ATTR(in9, lcrit, SMM665_MISC16_ADC_DATA_AIN1);
+SMM665_ATTR(in10, lcrit, SMM665_MISC16_ADC_DATA_AIN2);
+
+/* Input voltages crit */
+SMM665_ATTR(in1, crit, SMM665_MISC16_ADC_DATA_12V);
+SMM665_ATTR(in2, crit, SMM665_MISC16_ADC_DATA_VDD);
+SMM665_ATTR(in3, crit, SMM665_MISC16_ADC_DATA_A);
+SMM665_ATTR(in4, crit, SMM665_MISC16_ADC_DATA_B);
+SMM665_ATTR(in5, crit, SMM665_MISC16_ADC_DATA_C);
+SMM665_ATTR(in6, crit, SMM665_MISC16_ADC_DATA_D);
+SMM665_ATTR(in7, crit, SMM665_MISC16_ADC_DATA_E);
+SMM665_ATTR(in8, crit, SMM665_MISC16_ADC_DATA_F);
+SMM665_ATTR(in9, crit, SMM665_MISC16_ADC_DATA_AIN1);
+SMM665_ATTR(in10, crit, SMM665_MISC16_ADC_DATA_AIN2);
+
+/* critical alarms */
+SMM665_ATTR(in1, crit_alarm, SMM665_FAULT_12V);
+SMM665_ATTR(in2, crit_alarm, SMM665_FAULT_VDD);
+SMM665_ATTR(in3, crit_alarm, SMM665_FAULT_A);
+SMM665_ATTR(in4, crit_alarm, SMM665_FAULT_B);
+SMM665_ATTR(in5, crit_alarm, SMM665_FAULT_C);
+SMM665_ATTR(in6, crit_alarm, SMM665_FAULT_D);
+SMM665_ATTR(in7, crit_alarm, SMM665_FAULT_E);
+SMM665_ATTR(in8, crit_alarm, SMM665_FAULT_F);
+SMM665_ATTR(in9, crit_alarm, SMM665_FAULT_AIN1);
+SMM665_ATTR(in10, crit_alarm, SMM665_FAULT_AIN2);
+
+/* Temperature */
+SMM665_ATTR(temp1, input, SMM665_MISC16_ADC_DATA_INT_TEMP);
+SMM665_ATTR(temp1, min, SMM665_MISC16_ADC_DATA_INT_TEMP);
+SMM665_ATTR(temp1, max, SMM665_MISC16_ADC_DATA_INT_TEMP);
+SMM665_ATTR(temp1, lcrit, SMM665_MISC16_ADC_DATA_INT_TEMP);
+SMM665_ATTR(temp1, crit, SMM665_MISC16_ADC_DATA_INT_TEMP);
+SMM665_ATTR(temp1, crit_alarm, SMM665_FAULT_TEMP);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *smm665_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in1_crit.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in2_crit.dev_attr.attr,
+	&sensor_dev_attr_in2_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in3_crit.dev_attr.attr,
+	&sensor_dev_attr_in3_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in4_crit.dev_attr.attr,
+	&sensor_dev_attr_in4_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in5_crit.dev_attr.attr,
+	&sensor_dev_attr_in5_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in6_crit.dev_attr.attr,
+	&sensor_dev_attr_in6_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in7_crit.dev_attr.attr,
+	&sensor_dev_attr_in7_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in8_min.dev_attr.attr,
+	&sensor_dev_attr_in8_max.dev_attr.attr,
+	&sensor_dev_attr_in8_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in8_crit.dev_attr.attr,
+	&sensor_dev_attr_in8_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in9_min.dev_attr.attr,
+	&sensor_dev_attr_in9_max.dev_attr.attr,
+	&sensor_dev_attr_in9_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in9_crit.dev_attr.attr,
+	&sensor_dev_attr_in9_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in10_min.dev_attr.attr,
+	&sensor_dev_attr_in10_max.dev_attr.attr,
+	&sensor_dev_attr_in10_lcrit.dev_attr.attr,
+	&sensor_dev_attr_in10_crit.dev_attr.attr,
+	&sensor_dev_attr_in10_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_lcrit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(smm665);
+
+static int smm665_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct smm665_data *data;
+	struct device *hwmon_dev;
+	int i, ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+				     | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	if (i2c_smbus_read_byte_data(client, SMM665_ADOC_ENABLE) < 0)
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	data->client = client;
+	data->type = id->driver_data;
+	data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK)
+				     | SMM665_CMDREG_BASE);
+	if (!data->cmdreg)
+		return -ENOMEM;
+
+	switch (data->type) {
+	case smm465:
+	case smm665:
+		data->conversion_time = SMM665_ADC_WAIT_SMM665;
+		break;
+	case smm665c:
+	case smm764:
+	case smm766:
+		data->conversion_time = SMM665_ADC_WAIT_SMM766;
+		break;
+	}
+
+	ret = -ENODEV;
+	if (i2c_smbus_read_byte_data(data->cmdreg, SMM665_MISC8_CMD_STS) < 0)
+		goto out_unregister;
+
+	/*
+	 * Read limits.
+	 *
+	 * Limit registers start with register SMM665_LIMIT_BASE.
+	 * Each channel uses 8 registers, providing four limit values
+	 * per channel. Each limit value requires two registers, with the
+	 * high byte in the first register and the low byte in the second
+	 * register. The first two limits are under limit values, followed
+	 * by two over limit values.
+	 *
+	 * Limit register order matches the ADC register order, so we use
+	 * ADC register defines throughout the code to index limit registers.
+	 *
+	 * We save the first retrieved value both as "critical" and "alarm"
+	 * value. The second value overwrites either the critical or the
+	 * alarm value, depending on its configuration. This ensures that both
+	 * critical and alarm values are initialized, even if both registers are
+	 * configured as critical or non-critical.
+	 */
+	for (i = 0; i < SMM665_NUM_ADC; i++) {
+		int val;
+
+		val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8);
+		if (unlikely(val < 0))
+			goto out_unregister;
+		data->critical_min_limit[i] = data->alarm_min_limit[i]
+		  = smm665_convert(val, i);
+		val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 2);
+		if (unlikely(val < 0))
+			goto out_unregister;
+		if (smm665_is_critical(val))
+			data->critical_min_limit[i] = smm665_convert(val, i);
+		else
+			data->alarm_min_limit[i] = smm665_convert(val, i);
+		val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 4);
+		if (unlikely(val < 0))
+			goto out_unregister;
+		data->critical_max_limit[i] = data->alarm_max_limit[i]
+		  = smm665_convert(val, i);
+		val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 6);
+		if (unlikely(val < 0))
+			goto out_unregister;
+		if (smm665_is_critical(val))
+			data->critical_max_limit[i] = smm665_convert(val, i);
+		else
+			data->alarm_max_limit[i] = smm665_convert(val, i);
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   smm665_groups);
+	if (IS_ERR(hwmon_dev)) {
+		ret = PTR_ERR(hwmon_dev);
+		goto out_unregister;
+	}
+
+	return 0;
+
+out_unregister:
+	i2c_unregister_device(data->cmdreg);
+	return ret;
+}
+
+static int smm665_remove(struct i2c_client *client)
+{
+	struct smm665_data *data = i2c_get_clientdata(client);
+
+	i2c_unregister_device(data->cmdreg);
+	return 0;
+}
+
+static const struct i2c_device_id smm665_id[] = {
+	{"smm465", smm465},
+	{"smm665", smm665},
+	{"smm665c", smm665c},
+	{"smm764", smm764},
+	{"smm766", smm766},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, smm665_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver smm665_driver = {
+	.driver = {
+		   .name = "smm665",
+		   },
+	.probe = smm665_probe,
+	.remove = smm665_remove,
+	.id_table = smm665_id,
+};
+
+module_i2c_driver(smm665_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("SMM665 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
new file mode 100644
index 0000000..6bd2007
--- /dev/null
+++ b/drivers/hwmon/smsc47b397.c
@@ -0,0 +1,374 @@
+/*
+ * smsc47b397.c - Part of lm_sensors, Linux kernel modules
+ * for hardware monitoring
+ *
+ * Supports the SMSC LPC47B397-NC Super-I/O chip.
+ *
+ * Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+ * Copyright (C) 2004 Utilitek Systems, Inc.
+ *
+ * derived in part from smsc47m1.c:
+ * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004 Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47b397"
+
+/* Super-I/0 registers and commands */
+
+#define	REG	0x2e	/* The register to read/write */
+#define	VAL	0x2f	/* The value to read/write */
+
+static inline void superio_outb(int reg, int val)
+{
+	outb(reg, REG);
+	outb(val, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+/* select superio logical device */
+static inline void superio_select(int ld)
+{
+	superio_outb(0x07, ld);
+}
+
+static inline void superio_enter(void)
+{
+	outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+	outb(0xAA, REG);
+}
+
+#define SUPERIO_REG_DEVID	0x20
+#define SUPERIO_REG_DEVREV	0x21
+#define SUPERIO_REG_BASE_MSB	0x60
+#define SUPERIO_REG_BASE_LSB	0x61
+#define SUPERIO_REG_LD8		0x08
+
+#define SMSC_EXTENT		0x02
+
+/* 0 <= nr <= 3 */
+static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
+#define SMSC47B397_REG_TEMP(nr)	(smsc47b397_reg_temp[(nr)])
+
+/* 0 <= nr <= 3 */
+#define SMSC47B397_REG_FAN_LSB(nr) (0x28 + 2 * (nr))
+#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr))
+
+struct smsc47b397_data {
+	unsigned short addr;
+	struct mutex lock;
+
+	struct mutex update_lock;
+	unsigned long last_updated; /* in jiffies */
+	int valid;
+
+	/* register values */
+	u16 fan[4];
+	u8 temp[4];
+};
+
+static int smsc47b397_read_value(struct smsc47b397_data *data, u8 reg)
+{
+	int res;
+
+	mutex_lock(&data->lock);
+	outb(reg, data->addr);
+	res = inb_p(data->addr + 1);
+	mutex_unlock(&data->lock);
+	return res;
+}
+
+static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
+{
+	struct smsc47b397_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		dev_dbg(dev, "starting device update...\n");
+
+		/* 4 temperature inputs, 4 fan inputs */
+		for (i = 0; i < 4; i++) {
+			data->temp[i] = smsc47b397_read_value(data,
+					SMSC47B397_REG_TEMP(i));
+
+			/* must read LSB first */
+			data->fan[i]  = smsc47b397_read_value(data,
+					SMSC47B397_REG_FAN_LSB(i));
+			data->fan[i] |= smsc47b397_read_value(data,
+					SMSC47B397_REG_FAN_MSB(i)) << 8;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+
+		dev_dbg(dev, "... device update complete\n");
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * TEMP: 0.001C/bit (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static int temp_from_reg(u8 reg)
+{
+	return (s8)reg * 1000;
+}
+
+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 smsc47b397_data *data = smsc47b397_update_device(dev);
+	return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+
+/*
+ * FAN: 1 RPM/bit
+ * REG: count of 90kHz pulses / revolution
+ */
+static int fan_from_reg(u16 reg)
+{
+	if (reg == 0 || reg == 0xffff)
+		return 0;
+	return 90000 * 60 / reg;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute
+			*devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47b397_data *data = smsc47b397_update_device(dev);
+	return sprintf(buf, "%d\n", fan_from_reg(data->fan[attr->index]));
+}
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static struct attribute *smsc47b397_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+
+	NULL
+};
+
+ATTRIBUTE_GROUPS(smsc47b397);
+
+static int smsc47b397_probe(struct platform_device *pdev);
+
+static struct platform_driver smsc47b397_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.probe		= smsc47b397_probe,
+};
+
+static int smsc47b397_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct smsc47b397_data *data;
+	struct device *hwmon_dev;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start, SMSC_EXTENT,
+				 smsc47b397_driver.driver.name)) {
+		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start,
+			(unsigned long)res->start + SMSC_EXTENT - 1);
+		return -EBUSY;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct smsc47b397_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = res->start;
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "smsc47b397",
+							   data,
+							   smsc47b397_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static int __init smsc47b397_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SMSC_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init smsc47b397_find(void)
+{
+	u8 id, rev;
+	char *name;
+	unsigned short addr;
+
+	superio_enter();
+	id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
+
+	switch (id) {
+	case 0x81:
+		name = "SCH5307-NS";
+		break;
+	case 0x6f:
+		name = "LPC47B397-NC";
+		break;
+	case 0x85:
+	case 0x8c:
+		name = "SCH5317";
+		break;
+	default:
+		superio_exit();
+		return -ENODEV;
+	}
+
+	rev = superio_inb(SUPERIO_REG_DEVREV);
+
+	superio_select(SUPERIO_REG_LD8);
+	addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
+		 |  superio_inb(SUPERIO_REG_BASE_LSB);
+
+	pr_info("found SMSC %s (base address 0x%04x, revision %u)\n",
+		name, addr, rev);
+
+	superio_exit();
+	return addr;
+}
+
+static int __init smsc47b397_init(void)
+{
+	unsigned short address;
+	int ret;
+
+	ret = smsc47b397_find();
+	if (ret < 0)
+		return ret;
+	address = ret;
+
+	ret = platform_driver_register(&smsc47b397_driver);
+	if (ret)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	ret = smsc47b397_device_add(address);
+	if (ret)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&smsc47b397_driver);
+exit:
+	return ret;
+}
+
+static void __exit smsc47b397_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&smsc47b397_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("SMSC LPC47B397 driver");
+MODULE_LICENSE("GPL");
+
+module_init(smsc47b397_init);
+module_exit(smsc47b397_exit);
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
new file mode 100644
index 0000000..5d32318
--- /dev/null
+++ b/drivers/hwmon/smsc47m1.c
@@ -0,0 +1,946 @@
+/*
+ * smsc47m1.c - Part of lm_sensors, Linux kernel modules
+ *		for hardware monitoring
+ *
+ * Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
+ * LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
+ * Super-I/O chips.
+ *
+ * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004-2007 Jean Delvare <jdelvare@suse.de>
+ * Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
+ *			and Jean Delvare
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47m1"
+enum chips { smsc47m1, smsc47m2 };
+
+/* Super-I/0 registers and commands */
+
+#define REG	0x2e	/* The register to read/write */
+#define VAL	0x2f	/* The value to read/write */
+
+static inline void
+superio_outb(int reg, int val)
+{
+	outb(reg, REG);
+	outb(val, VAL);
+}
+
+static inline int
+superio_inb(int reg)
+{
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+/* logical device for fans is 0x0A */
+#define superio_select() superio_outb(0x07, 0x0A)
+
+static inline void
+superio_enter(void)
+{
+	outb(0x55, REG);
+}
+
+static inline void
+superio_exit(void)
+{
+	outb(0xAA, REG);
+}
+
+#define SUPERIO_REG_ACT		0x30
+#define SUPERIO_REG_BASE	0x60
+#define SUPERIO_REG_DEVID	0x20
+#define SUPERIO_REG_DEVREV	0x21
+
+/* Logical device registers */
+
+#define SMSC_EXTENT		0x80
+
+/* nr is 0 or 1 in the macros below */
+#define SMSC47M1_REG_ALARM		0x04
+#define SMSC47M1_REG_TPIN(nr)		(0x34 - (nr))
+#define SMSC47M1_REG_PPIN(nr)		(0x36 - (nr))
+#define SMSC47M1_REG_FANDIV		0x58
+
+static const u8 SMSC47M1_REG_FAN[3]		= { 0x59, 0x5a, 0x6b };
+static const u8 SMSC47M1_REG_FAN_PRELOAD[3]	= { 0x5b, 0x5c, 0x6c };
+static const u8 SMSC47M1_REG_PWM[3]		= { 0x56, 0x57, 0x69 };
+
+#define SMSC47M2_REG_ALARM6		0x09
+#define SMSC47M2_REG_TPIN1		0x38
+#define SMSC47M2_REG_TPIN2		0x37
+#define SMSC47M2_REG_TPIN3		0x2d
+#define SMSC47M2_REG_PPIN3		0x2c
+#define SMSC47M2_REG_FANDIV3		0x6a
+
+#define MIN_FROM_REG(reg, div)		((reg) >= 192 ? 0 : \
+					 983040 / ((192 - (reg)) * (div)))
+#define FAN_FROM_REG(reg, div, preload)	((reg) <= (preload) || (reg) == 255 ? \
+					 0 : \
+					 983040 / (((reg) - (preload)) * (div)))
+#define DIV_FROM_REG(reg)		(1 << (reg))
+#define PWM_FROM_REG(reg)		(((reg) & 0x7E) << 1)
+#define PWM_EN_FROM_REG(reg)		((~(reg)) & 0x01)
+#define PWM_TO_REG(reg)			(((reg) >> 1) & 0x7E)
+
+struct smsc47m1_data {
+	unsigned short addr;
+	const char *name;
+	enum chips type;
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 fan[3];		/* Register value */
+	u8 fan_preload[3];	/* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 alarms;		/* Register encoding */
+	u8 pwm[3];		/* Register value (bit 0 is disable) */
+};
+
+struct smsc47m1_sio_data {
+	enum chips type;
+	u8 activate;		/* Remember initial device state */
+};
+
+static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
+{
+	return inb_p(data->addr + reg);
+}
+
+static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
+		u8 value)
+{
+	outb_p(value, data->addr + reg);
+}
+
+static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
+		int init)
+{
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
+		int i, fan_nr;
+		fan_nr = data->type == smsc47m2 ? 3 : 2;
+
+		for (i = 0; i < fan_nr; i++) {
+			data->fan[i] = smsc47m1_read_value(data,
+				       SMSC47M1_REG_FAN[i]);
+			data->fan_preload[i] = smsc47m1_read_value(data,
+					       SMSC47M1_REG_FAN_PRELOAD[i]);
+			data->pwm[i] = smsc47m1_read_value(data,
+				       SMSC47M1_REG_PWM[i]);
+		}
+
+		i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = i >> 6;
+
+		data->alarms = smsc47m1_read_value(data,
+			       SMSC47M1_REG_ALARM) >> 6;
+		/* Clear alarms if needed */
+		if (data->alarms)
+			smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
+
+		if (fan_nr >= 3) {
+			data->fan_div[2] = (smsc47m1_read_value(data,
+					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
+			data->alarms |= (smsc47m1_read_value(data,
+					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
+			/* Clear alarm if needed */
+			if (data->alarms & 0x04)
+				smsc47m1_write_value(data,
+						     SMSC47M2_REG_ALARM6,
+						     0x40);
+		}
+
+		data->last_updated = jiffies;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static ssize_t get_fan(struct device *dev, struct device_attribute
+		       *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	int nr = attr->index;
+	/*
+	 * This chip (stupidly) stops monitoring fan speed if PWM is
+	 * enabled and duty cycle is 0%. This is fine if the monitoring
+	 * and control concern the same fan, but troublesome if they are
+	 * not (which could as well happen).
+	 */
+	int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
+		  FAN_FROM_REG(data->fan[nr],
+			       DIV_FROM_REG(data->fan_div[nr]),
+			       data->fan_preload[nr]);
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t get_fan_min(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	int nr = attr->index;
+	int rpm = MIN_FROM_REG(data->fan_preload[nr],
+			       DIV_FROM_REG(data->fan_div[nr]));
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t get_fan_div(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+static ssize_t get_fan_alarm(struct device *dev, struct device_attribute
+			     *devattr, char *buf)
+{
+	int bitnr = to_sensor_dev_attr(devattr)->index;
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static ssize_t get_pwm(struct device *dev, struct device_attribute
+		       *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
+}
+
+static ssize_t get_pwm_en(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
+}
+
+static ssize_t get_alarms(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	long rpmdiv;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
+
+	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
+	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
+			     data->fan_preload[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan clock divider.  This follows the principle
+ * of least surprise; the user doesn't expect the fan minimum to change just
+ * because the divider changed.
+ */
+static ssize_t set_fan_div(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	long new_div;
+	int err;
+	long tmp;
+	u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
+
+	err = kstrtol(buf, 10, &new_div);
+	if (err)
+		return err;
+
+	if (new_div == old_div) /* No change */
+		return count;
+
+	mutex_lock(&data->update_lock);
+	switch (new_div) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	switch (nr) {
+	case 0:
+	case 1:
+		tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
+		      & ~(0x03 << (4 + 2 * nr));
+		tmp |= data->fan_div[nr] << (4 + 2 * nr);
+		smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
+		break;
+	case 2:
+		tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
+		tmp |= data->fan_div[2] << 4;
+		smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
+		break;
+	}
+
+	/* Preserve fan min */
+	tmp = 192 - (old_div * (192 - data->fan_preload[nr])
+		     + new_div / 2) / new_div;
+	data->fan_preload[nr] = clamp_val(tmp, 0, 191);
+	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
+			     data->fan_preload[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute
+		       *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] &= 0x81; /* Preserve additional bits */
+	data->pwm[nr] |= PWM_TO_REG(val);
+	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
+			     data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t set_pwm_en(struct device *dev, struct device_attribute
+			  *devattr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] &= 0xFE; /* preserve the other bits */
+	data->pwm[nr] |= !val;
+	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
+			     data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define fan_present(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan,	\
+		NULL, offset - 1);					\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		get_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		get_fan_div, set_fan_div, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm,	\
+		NULL, offset - 1);					\
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,		\
+		get_pwm, set_pwm, offset - 1);				\
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,	\
+		get_pwm_en, set_pwm_en, offset - 1)
+
+fan_present(1);
+fan_present(2);
+fan_present(3);
+
+static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *smsc47m1_attributes_fan1[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_fan1 = {
+	.attrs = smsc47m1_attributes_fan1,
+};
+
+static struct attribute *smsc47m1_attributes_fan2[] = {
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_fan2 = {
+	.attrs = smsc47m1_attributes_fan2,
+};
+
+static struct attribute *smsc47m1_attributes_fan3[] = {
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_fan3 = {
+	.attrs = smsc47m1_attributes_fan3,
+};
+
+static struct attribute *smsc47m1_attributes_pwm1[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_pwm1 = {
+	.attrs = smsc47m1_attributes_pwm1,
+};
+
+static struct attribute *smsc47m1_attributes_pwm2[] = {
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_pwm2 = {
+	.attrs = smsc47m1_attributes_pwm2,
+};
+
+static struct attribute *smsc47m1_attributes_pwm3[] = {
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group_pwm3 = {
+	.attrs = smsc47m1_attributes_pwm3,
+};
+
+static struct attribute *smsc47m1_attributes[] = {
+	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m1_group = {
+	.attrs = smsc47m1_attributes,
+};
+
+static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data)
+{
+	u8 val;
+	unsigned short addr;
+
+	superio_enter();
+	val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
+
+	/*
+	 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
+	 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
+	 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
+	 * can do much more besides (device id 0x60).
+	 * The LPC47M997 is undocumented, but seems to be compatible with
+	 * the LPC47M192, and has the same device id.
+	 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
+	 * supports a 3rd fan, and the pin configuration registers are
+	 * unfortunately different.
+	 * The LPC47M233 has the same device id (0x6B) but is not compatible.
+	 * We check the high bit of the device revision register to
+	 * differentiate them.
+	 */
+	switch (val) {
+	case 0x51:
+		pr_info("Found SMSC LPC47B27x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x59:
+		pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x5F:
+		pr_info("Found SMSC LPC47M14x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x60:
+		pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x6B:
+		if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
+			pr_debug("Found SMSC LPC47M233, unsupported\n");
+			superio_exit();
+			return -ENODEV;
+		}
+
+		pr_info("Found SMSC LPC47M292\n");
+		sio_data->type = smsc47m2;
+		break;
+	default:
+		superio_exit();
+		return -ENODEV;
+	}
+
+	superio_select();
+	addr = (superio_inb(SUPERIO_REG_BASE) << 8)
+	      |  superio_inb(SUPERIO_REG_BASE + 1);
+	if (addr == 0) {
+		pr_info("Device address not set, will not use\n");
+		superio_exit();
+		return -ENODEV;
+	}
+
+	/*
+	 * Enable only if address is set (needed at least on the
+	 * Compaq Presario S4000NX)
+	 */
+	sio_data->activate = superio_inb(SUPERIO_REG_ACT);
+	if ((sio_data->activate & 0x01) == 0) {
+		pr_info("Enabling device\n");
+		superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
+	}
+
+	superio_exit();
+	return addr;
+}
+
+/* Restore device to its initial state */
+static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
+{
+	if ((sio_data->activate & 0x01) == 0) {
+		superio_enter();
+		superio_select();
+
+		pr_info("Disabling device\n");
+		superio_outb(SUPERIO_REG_ACT, sio_data->activate);
+
+		superio_exit();
+	}
+}
+
+#define CHECK		1
+#define REQUEST		2
+
+/*
+ * This function can be used to:
+ *  - test for resource conflicts with ACPI
+ *  - request the resources
+ * We only allocate the I/O ports we really need, to minimize the risk of
+ * conflicts with ACPI or with other drivers.
+ */
+static int __init smsc47m1_handle_resources(unsigned short address,
+					    enum chips type, int action,
+					    struct device *dev)
+{
+	static const u8 ports_m1[] = {
+		/* register, region length */
+		0x04, 1,
+		0x33, 4,
+		0x56, 7,
+	};
+
+	static const u8 ports_m2[] = {
+		/* register, region length */
+		0x04, 1,
+		0x09, 1,
+		0x2c, 2,
+		0x35, 4,
+		0x56, 7,
+		0x69, 4,
+	};
+
+	int i, ports_size, err;
+	const u8 *ports;
+
+	switch (type) {
+	case smsc47m1:
+	default:
+		ports = ports_m1;
+		ports_size = ARRAY_SIZE(ports_m1);
+		break;
+	case smsc47m2:
+		ports = ports_m2;
+		ports_size = ARRAY_SIZE(ports_m2);
+		break;
+	}
+
+	for (i = 0; i + 1 < ports_size; i += 2) {
+		unsigned short start = address + ports[i];
+		unsigned short len = ports[i + 1];
+
+		switch (action) {
+		case CHECK:
+			/* Only check for conflicts */
+			err = acpi_check_region(start, len, DRVNAME);
+			if (err)
+				return err;
+			break;
+		case REQUEST:
+			/* Request the resources */
+			if (!devm_request_region(dev, start, len, DRVNAME)) {
+				dev_err(dev,
+					"Region 0x%hx-0x%hx already in use!\n",
+					start, start + len);
+				return -EBUSY;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void smsc47m1_remove_files(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan1);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan2);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan3);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm1);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm2);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm3);
+}
+
+static int __init smsc47m1_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct smsc47m1_sio_data *sio_data = dev_get_platdata(dev);
+	struct smsc47m1_data *data;
+	struct resource *res;
+	int err;
+	int fan1, fan2, fan3, pwm1, pwm2, pwm3;
+
+	static const char * const names[] = {
+		"smsc47m1",
+		"smsc47m2",
+	};
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	err = smsc47m1_handle_resources(res->start, sio_data->type,
+					REQUEST, dev);
+	if (err < 0)
+		return err;
+
+	data = devm_kzalloc(dev, sizeof(struct smsc47m1_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->name = names[sio_data->type];
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	/*
+	 * If no function is properly configured, there's no point in
+	 * actually registering the chip.
+	 */
+	pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
+	       == 0x04;
+	pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
+	       == 0x04;
+	if (data->type == smsc47m2) {
+		fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
+			& 0x0d) == 0x09;
+		fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
+			& 0x0d) == 0x09;
+		fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
+			& 0x0d) == 0x0d;
+		pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
+			& 0x0d) == 0x08;
+	} else {
+		fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
+			& 0x05) == 0x05;
+		fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
+			& 0x05) == 0x05;
+		fan3 = 0;
+		pwm3 = 0;
+	}
+	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
+		dev_warn(dev, "Device not configured, will not use\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Some values (fan min, clock dividers, pwm registers) may be
+	 * needed before any update is triggered, so we better read them
+	 * at least once here. We don't usually do it that way, but in
+	 * this particular case, manually reading 5 registers out of 8
+	 * doesn't make much sense and we're better using the existing
+	 * function.
+	 */
+	smsc47m1_update_device(dev, 1);
+
+	/* Register sysfs hooks */
+	if (fan1) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_fan1);
+		if (err)
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
+
+	if (fan2) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_fan2);
+		if (err)
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
+
+	if (fan3) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_fan3);
+		if (err)
+			goto error_remove_files;
+	} else if (data->type == smsc47m2)
+		dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
+
+	if (pwm1) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_pwm1);
+		if (err)
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
+
+	if (pwm2) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_pwm2);
+		if (err)
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
+
+	if (pwm3) {
+		err = sysfs_create_group(&dev->kobj,
+					 &smsc47m1_group_pwm3);
+		if (err)
+			goto error_remove_files;
+	} else if (data->type == smsc47m2)
+		dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
+
+	err = sysfs_create_group(&dev->kobj, &smsc47m1_group);
+	if (err)
+		goto error_remove_files;
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error_remove_files;
+	}
+
+	return 0;
+
+error_remove_files:
+	smsc47m1_remove_files(dev);
+	return err;
+}
+
+static int __exit smsc47m1_remove(struct platform_device *pdev)
+{
+	struct smsc47m1_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	smsc47m1_remove_files(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver smsc47m1_driver = {
+	.driver = {
+		.name	= DRVNAME,
+	},
+	.remove		= __exit_p(smsc47m1_remove),
+};
+
+static int __init smsc47m1_device_add(unsigned short address,
+				      const struct smsc47m1_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SMSC_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct smsc47m1_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init sm_smsc47m1_init(void)
+{
+	int err;
+	unsigned short address;
+	struct smsc47m1_sio_data sio_data;
+
+	err = smsc47m1_find(&sio_data);
+	if (err < 0)
+		return err;
+	address = err;
+
+	/* Sets global pdev as a side effect */
+	err = smsc47m1_device_add(address, &sio_data);
+	if (err)
+		return err;
+
+	err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe);
+	if (err)
+		goto exit_device;
+
+	return 0;
+
+exit_device:
+	platform_device_unregister(pdev);
+	smsc47m1_restore(&sio_data);
+	return err;
+}
+
+static void __exit sm_smsc47m1_exit(void)
+{
+	platform_driver_unregister(&smsc47m1_driver);
+	smsc47m1_restore(dev_get_platdata(&pdev->dev));
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
+MODULE_LICENSE("GPL");
+
+module_init(sm_smsc47m1_init);
+module_exit(sm_smsc47m1_exit);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
new file mode 100644
index 0000000..6ac7cda
--- /dev/null
+++ b/drivers/hwmon/smsc47m192.c
@@ -0,0 +1,644 @@
+/*
+ * smsc47m192.c - Support for hardware monitoring block of
+ *		  SMSC LPC47M192 and compatible Super I/O chips
+ *
+ * Copyright (C) 2006  Hartmut Rick <linux@rick.claranet.de>
+ *
+ * Derived from lm78.c and other chip drivers.
+ *
+ * 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/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+
+/* SMSC47M192 registers */
+#define SMSC47M192_REG_IN(nr)		((nr) < 6 ? (0x20 + (nr)) : \
+					(0x50 + (nr) - 6))
+#define SMSC47M192_REG_IN_MAX(nr)	((nr) < 6 ? (0x2b + (nr) * 2) : \
+					(0x54 + (((nr) - 6) * 2)))
+#define SMSC47M192_REG_IN_MIN(nr)	((nr) < 6 ? (0x2c + (nr) * 2) : \
+					(0x55 + (((nr) - 6) * 2)))
+static u8 SMSC47M192_REG_TEMP[3] =	{ 0x27, 0x26, 0x52 };
+static u8 SMSC47M192_REG_TEMP_MAX[3] =	{ 0x39, 0x37, 0x58 };
+static u8 SMSC47M192_REG_TEMP_MIN[3] =	{ 0x3A, 0x38, 0x59 };
+#define SMSC47M192_REG_TEMP_OFFSET(nr)	((nr) == 2 ? 0x1e : 0x1f)
+#define SMSC47M192_REG_ALARM1		0x41
+#define SMSC47M192_REG_ALARM2		0x42
+#define SMSC47M192_REG_VID		0x47
+#define SMSC47M192_REG_VID4		0x49
+#define SMSC47M192_REG_CONFIG		0x40
+#define SMSC47M192_REG_SFR		0x4f
+#define SMSC47M192_REG_COMPANY_ID	0x3e
+#define SMSC47M192_REG_VERSION		0x3f
+
+/* generalised scaling with integer rounding */
+static inline int SCALE(long val, int mul, int div)
+{
+	if (val < 0)
+		return (val * mul - div / 2) / div;
+	else
+		return (val * mul + div / 2) / div;
+}
+
+/* Conversions */
+
+/* smsc47m192 internally scales voltage measurements */
+static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };
+
+static inline unsigned int IN_FROM_REG(u8 reg, int n)
+{
+	return SCALE(reg, nom_mv[n], 192);
+}
+
+static inline u8 IN_TO_REG(unsigned long val, int n)
+{
+	return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
+}
+
+/*
+ * TEMP: 0.001 degC units (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static inline s8 TEMP_TO_REG(int val)
+{
+	return SCALE(clamp_val(val, -128000, 127000), 1, 1000);
+}
+
+static inline int TEMP_FROM_REG(s8 val)
+{
+	return val * 1000;
+}
+
+struct smsc47m192_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[8];		/* Register value */
+	u8 in_max[8];		/* Register value */
+	u8 in_min[8];		/* Register value */
+	s8 temp[3];		/* Register value */
+	s8 temp_max[3];		/* Register value */
+	s8 temp_min[3];		/* Register value */
+	s8 temp_offset[3];	/* Register value */
+	u16 alarms;		/* Register encoding, combined */
+	u8 vid;			/* Register encoding, combined */
+	u8 vrm;
+};
+
+static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
+{
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i, config;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	 || !data->valid) {
+		u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+
+		dev_dbg(&client->dev, "Starting smsc47m192 update\n");
+
+		for (i = 0; i <= 7; i++) {
+			data->in[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_IN(i));
+			data->in_min[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_IN_MIN(i));
+			data->in_max[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 3; i++) {
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_TEMP[i]);
+			data->temp_max[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_TEMP_MAX[i]);
+			data->temp_min[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_TEMP_MIN[i]);
+		}
+		for (i = 1; i < 3; i++)
+			data->temp_offset[i] = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_TEMP_OFFSET(i));
+		/*
+		 * first offset is temp_offset[0] if SFR bit 4 is set,
+		 * temp_offset[1] otherwise
+		 */
+		if (sfr & 0x10) {
+			data->temp_offset[0] = data->temp_offset[1];
+			data->temp_offset[1] = 0;
+		} else
+			data->temp_offset[0] = 0;
+
+		data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
+			    & 0x0f;
+		config = i2c_smbus_read_byte_data(client,
+						  SMSC47M192_REG_CONFIG);
+		if (config & 0x20)
+			data->vid |= (i2c_smbus_read_byte_data(client,
+					SMSC47M192_REG_VID4) & 0x01) << 4;
+		data->alarms = i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_ALARM1) |
+			       (i2c_smbus_read_byte_data(client,
+						SMSC47M192_REG_ALARM2) << 8);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* Voltages */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val, nr);
+	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
+							data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val, nr);
+	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
+							data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_in_offset(offset)					\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
+
+show_in_offset(0)
+show_in_offset(1)
+show_in_offset(2)
+show_in_offset(3)
+show_in_offset(4)
+show_in_offset(5)
+show_in_offset(6)
+show_in_offset(7)
+
+/* Temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
+						data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = TEMP_TO_REG(val);
+	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
+						data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_offset(struct device *dev, struct device_attribute
+		*attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
+}
+
+static ssize_t set_temp_offset(struct device *dev, struct device_attribute
+		*attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_offset[nr] = TEMP_TO_REG(val);
+	if (nr > 1)
+		i2c_smbus_write_byte_data(client,
+			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
+	else if (data->temp_offset[nr] != 0) {
+		/*
+		 * offset[0] and offset[1] share the same register,
+		 * SFR bit 4 activates offset[0]
+		 */
+		i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
+					(sfr & 0xef) | (nr == 0 ? 0x10 : 0));
+		data->temp_offset[1-nr] = 0;
+		i2c_smbus_write_byte_data(client,
+			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
+	} else if ((sfr & 0x10) == (nr == 0 ? 0x10 : 0))
+		i2c_smbus_write_byte_data(client,
+					SMSC47M192_REG_TEMP_OFFSET(nr), 0);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_temp_index(index)						\
+static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO,			\
+		show_temp, NULL, index-1);				\
+static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR,		\
+		show_temp_min, set_temp_min, index-1);			\
+static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR,		\
+		show_temp_max, set_temp_max, index-1);			\
+static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR,	\
+		show_temp_offset, set_temp_offset, index-1);
+
+show_temp_index(1)
+show_temp_index(2)
+show_temp_index(3)
+
+/* VID */
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct smsc47m192_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+/* Alarms */
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct smsc47m192_data *data = smsc47m192_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
+
+static struct attribute *smsc47m192_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_offset.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_offset.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_offset.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m192_group = {
+	.attrs = smsc47m192_attributes,
+};
+
+static struct attribute *smsc47m192_attributes_in4[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group smsc47m192_group_in4 = {
+	.attrs = smsc47m192_attributes_in4,
+};
+
+static void smsc47m192_init_client(struct i2c_client *client)
+{
+	int i;
+	u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
+	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+
+	/* select cycle mode (pause 1 sec between updates) */
+	i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
+						(sfr & 0xfd) | 0x02);
+	if (!(config & 0x01)) {
+		/* initialize alarm limits */
+		for (i = 0; i < 8; i++) {
+			i2c_smbus_write_byte_data(client,
+				SMSC47M192_REG_IN_MIN(i), 0);
+			i2c_smbus_write_byte_data(client,
+				SMSC47M192_REG_IN_MAX(i), 0xff);
+		}
+		for (i = 0; i < 3; i++) {
+			i2c_smbus_write_byte_data(client,
+				SMSC47M192_REG_TEMP_MIN[i], 0x80);
+			i2c_smbus_write_byte_data(client,
+				SMSC47M192_REG_TEMP_MAX[i], 0x7f);
+		}
+
+		/* start monitoring */
+		i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG,
+						(config & 0xf7) | 0x01);
+	}
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int smsc47m192_detect(struct i2c_client *client,
+			     struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int version;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Detection criteria from sensors_detect script */
+	version = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VERSION);
+	if (i2c_smbus_read_byte_data(client,
+				SMSC47M192_REG_COMPANY_ID) == 0x55
+	 && (version & 0xf0) == 0x20
+	 && (i2c_smbus_read_byte_data(client,
+				SMSC47M192_REG_VID) & 0x70) == 0x00
+	 && (i2c_smbus_read_byte_data(client,
+				SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
+		dev_info(&adapter->dev,
+			 "found SMSC47M192 or compatible, "
+			 "version 2, stepping A%d\n", version & 0x0f);
+	} else {
+		dev_dbg(&adapter->dev,
+			"SMSC47M192 detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int smsc47m192_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct smsc47m192_data *data;
+	int config;
+
+	data = devm_kzalloc(dev, sizeof(struct smsc47m192_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->vrm = vid_which_vrm();
+	mutex_init(&data->update_lock);
+
+	/* Initialize the SMSC47M192 chip */
+	smsc47m192_init_client(client);
+
+	/* sysfs hooks */
+	data->groups[0] = &smsc47m192_group;
+	/* Pin 110 is either in4 (+12V) or VID4 */
+	config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
+	if (!(config & 0x20))
+		data->groups[1] = &smsc47m192_group_in4;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id smsc47m192_id[] = {
+	{ "smsc47m192", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
+
+static struct i2c_driver smsc47m192_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "smsc47m192",
+	},
+	.probe		= smsc47m192_probe,
+	.id_table	= smsc47m192_id,
+	.detect		= smsc47m192_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(smsc47m192_driver);
+
+MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>");
+MODULE_DESCRIPTION("SMSC47M192 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c
new file mode 100644
index 0000000..d951651
--- /dev/null
+++ b/drivers/hwmon/tc74.c
@@ -0,0 +1,177 @@
+/*
+ * An hwmon driver for the Microchip TC74
+ *
+ * Copyright 2015 Maciej Szmigiero <mail@maciej.szmigiero.name>
+ *
+ * Based on ad7414.c:
+ *	Copyright 2006 Stefan Roese, DENX Software Engineering
+ *	Copyright 2008 Sean MacLennan, PIKA Technologies
+ *	Copyright 2008 Frank Edelhaeuser, Spansion Inc.
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+/* TC74 registers */
+#define TC74_REG_TEMP		0x00
+#define TC74_REG_CONFIG		0x01
+
+struct tc74_data {
+	struct i2c_client	*client;
+	struct mutex		lock;	/* atomic read data updates */
+	bool			valid;	/* validity of fields below */
+	unsigned long		next_update;	/* In jiffies */
+	s8			temp_input;	/* Temp value in dC */
+};
+
+static int tc74_update_device(struct device *dev)
+{
+	struct tc74_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int ret;
+
+	ret = mutex_lock_interruptible(&data->lock);
+	if (ret)
+		return ret;
+
+	if (time_after(jiffies, data->next_update) || !data->valid) {
+		s32 value;
+
+		value = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
+		if (value < 0) {
+			dev_dbg(&client->dev, "TC74_REG_CONFIG read err %d\n",
+				(int)value);
+
+			ret = value;
+			goto ret_unlock;
+		}
+
+		if (!(value & BIT(6))) {
+			/* not ready yet */
+
+			ret = -EAGAIN;
+			goto ret_unlock;
+		}
+
+		value = i2c_smbus_read_byte_data(client, TC74_REG_TEMP);
+		if (value < 0) {
+			dev_dbg(&client->dev, "TC74_REG_TEMP read err %d\n",
+				(int)value);
+
+			ret = value;
+			goto ret_unlock;
+		}
+
+		data->temp_input = value;
+		data->next_update = jiffies + HZ / 4;
+		data->valid = true;
+	}
+
+ret_unlock:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct tc74_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = tc74_update_device(dev);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d\n", data->temp_input * 1000);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+
+static struct attribute *tc74_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(tc74);
+
+static int tc74_probe(struct i2c_client *client,
+		      const struct i2c_device_id *dev_id)
+{
+	struct device *dev = &client->dev;
+	struct tc74_data *data;
+	struct device *hwmon_dev;
+	s32 conf;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EOPNOTSUPP;
+
+	data = devm_kzalloc(dev, sizeof(struct tc74_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->lock);
+
+	/* Make sure the chip is powered up. */
+	conf = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
+	if (conf < 0) {
+		dev_err(dev, "unable to read config register\n");
+
+		return conf;
+	}
+
+	if (conf & 0x3f) {
+		dev_err(dev, "invalid config register value\n");
+
+		return -ENODEV;
+	}
+
+	if (conf & BIT(7)) {
+		s32 ret;
+
+		conf &= ~BIT(7);
+
+		ret = i2c_smbus_write_byte_data(client, TC74_REG_CONFIG, conf);
+		if (ret)
+			dev_warn(dev, "unable to disable STANDBY\n");
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+							   client->name,
+							   data, tc74_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id tc74_id[] = {
+	{ "tc74", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tc74_id);
+
+static struct i2c_driver tc74_driver = {
+	.driver = {
+		.name	= "tc74",
+	},
+	.probe	= tc74_probe,
+	.id_table = tc74_id,
+};
+
+module_i2c_driver(tc74_driver);
+
+MODULE_AUTHOR("Maciej Szmigiero <mail@maciej.szmigiero.name>");
+
+MODULE_DESCRIPTION("TC74 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
new file mode 100644
index 0000000..6a0ee90
--- /dev/null
+++ b/drivers/hwmon/thmc50.c
@@ -0,0 +1,445 @@
+/*
+ * thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	      monitoring
+ * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
+ * Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and
+ * Philip Edelbrock <phil@netroedge.com>
+ *
+ * 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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+enum chips { thmc50, adm1022 };
+
+static unsigned short adm1022_temp3[16];
+static unsigned int adm1022_temp3_num;
+module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
+MODULE_PARM_DESC(adm1022_temp3,
+		 "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
+
+/* Many THMC50 constants specified below */
+
+/* The THMC50 registers */
+#define THMC50_REG_CONF				0x40
+#define THMC50_REG_COMPANY_ID			0x3E
+#define THMC50_REG_DIE_CODE			0x3F
+#define THMC50_REG_ANALOG_OUT			0x19
+/*
+ * The mirror status register cannot be used as
+ * reading it does not clear alarms.
+ */
+#define THMC50_REG_INTR				0x41
+
+static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
+static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
+static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
+static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 };
+static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 };
+
+#define THMC50_REG_CONF_nFANOFF			0x20
+#define THMC50_REG_CONF_PROGRAMMED		0x08
+
+/* Each client has this additional data */
+struct thmc50_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+
+	struct mutex update_lock;
+	enum chips type;
+	unsigned long last_updated;	/* In jiffies */
+	char has_temp3;		/* !=0 if it is ADM1022 in temp3 mode */
+	char valid;		/* !=0 if following fields are valid */
+
+	/* Register values */
+	s8 temp_input[3];
+	s8 temp_max[3];
+	s8 temp_min[3];
+	s8 temp_critical[3];
+	u8 analog_out;
+	u8 alarms;
+};
+
+static struct thmc50_data *thmc50_update_device(struct device *dev)
+{
+	struct thmc50_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + timeout)
+	    || !data->valid) {
+
+		int temps = data->has_temp3 ? 3 : 2;
+		int i;
+		int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+
+		prog &= THMC50_REG_CONF_PROGRAMMED;
+
+		for (i = 0; i < temps; i++) {
+			data->temp_input[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP[i]);
+			data->temp_max[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP_MAX[i]);
+			data->temp_min[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP_MIN[i]);
+			data->temp_critical[i] =
+				i2c_smbus_read_byte_data(client,
+					prog ? THMC50_REG_TEMP_CRITICAL[i]
+					     : THMC50_REG_TEMP_DEFAULT[i]);
+		}
+		data->analog_out =
+		    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+		data->alarms =
+		    i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t show_analog_out(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->analog_out);
+}
+
+static ssize_t set_analog_out(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct thmc50_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int config;
+	unsigned long tmp;
+	int err;
+
+	err = kstrtoul(buf, 10, &tmp);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->analog_out = clamp_val(tmp, 0, 255);
+	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+				  data->analog_out);
+
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+	if (data->analog_out == 0)
+		config &= ~THMC50_REG_CONF_nFANOFF;
+	else
+		config |= THMC50_REG_CONF_nFANOFF;
+	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* There is only one PWM mode = DC */
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	return sprintf(buf, "0\n");
+}
+
+/* Temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = clamp_val(val / 1000, -128, 127);
+	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
+				  data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = clamp_val(val / 1000, -128, 127);
+	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
+				  data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_critical(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+
+	return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
+#define temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,	\
+			NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
+			show_temp_min, set_temp_min, offset - 1);	\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+			show_temp_max, set_temp_max, offset - 1);	\
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO,			\
+			show_temp_critical, NULL, offset - 1);
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
+			  set_analog_out, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+
+static struct attribute *thmc50_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group thmc50_group = {
+	.attrs = thmc50_attributes,
+};
+
+/* for ADM1022 3rd temperature mode */
+static struct attribute *temp3_attributes[] = {
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group temp3_group = {
+	.attrs = temp3_attributes,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int thmc50_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	unsigned company;
+	unsigned revision;
+	unsigned config;
+	struct i2c_adapter *adapter = client->adapter;
+	const char *type_name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
+		return -ENODEV;
+	}
+
+	pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
+		 client->addr, i2c_adapter_id(client->adapter));
+
+	company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
+	revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+	if (revision < 0xc0 || (config & 0x10))
+		return -ENODEV;
+
+	if (company == 0x41) {
+		int id = i2c_adapter_id(client->adapter);
+		int i;
+
+		type_name = "adm1022";
+		for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
+			if (adm1022_temp3[i] == id &&
+			    adm1022_temp3[i + 1] == client->addr) {
+				/* enable 2nd remote temp */
+				config |= (1 << 7);
+				i2c_smbus_write_byte_data(client,
+							  THMC50_REG_CONF,
+							  config);
+				break;
+			}
+	} else if (company == 0x49) {
+		type_name = "thmc50";
+	} else {
+		pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
+		return -ENODEV;
+	}
+
+	pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+		 type_name, (revision >> 4) - 0xc, revision & 0xf);
+
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void thmc50_init_client(struct thmc50_data *data)
+{
+	struct i2c_client *client = data->client;
+	int config;
+
+	data->analog_out = i2c_smbus_read_byte_data(client,
+						    THMC50_REG_ANALOG_OUT);
+	/* set up to at least 1 */
+	if (data->analog_out == 0) {
+		data->analog_out = 1;
+		i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+					  data->analog_out);
+	}
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+	config |= 0x1;	/* start the chip if it is in standby mode */
+	if (data->type == adm1022 && (config & (1 << 7)))
+		data->has_temp3 = 1;
+	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+}
+
+static int thmc50_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct thmc50_data *data;
+	struct device *hwmon_dev;
+	int idx = 0;
+
+	data = devm_kzalloc(dev, sizeof(struct thmc50_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	data->type = id->driver_data;
+	mutex_init(&data->update_lock);
+
+	thmc50_init_client(data);
+
+	/* sysfs hooks */
+	data->groups[idx++] = &thmc50_group;
+
+	/* Register additional ADM1022 sysfs hooks */
+	if (data->has_temp3)
+		data->groups[idx++] = &temp3_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id thmc50_id[] = {
+	{ "adm1022", adm1022 },
+	{ "thmc50", thmc50 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, thmc50_id);
+
+static struct i2c_driver thmc50_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "thmc50",
+	},
+	.probe = thmc50_probe,
+	.id_table = thmc50_id,
+	.detect = thmc50_detect,
+	.address_list = normal_i2c,
+};
+
+module_i2c_driver(thmc50_driver);
+
+MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
+MODULE_DESCRIPTION("THMC50 driver");
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
new file mode 100644
index 0000000..5289aa0
--- /dev/null
+++ b/drivers/hwmon/tmp102.c
@@ -0,0 +1,318 @@
+/* Texas Instruments TMP102 SMBus temperature sensor driver
+ *
+ * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
+ *
+ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/thermal.h>
+#include <linux/of.h>
+
+#define	DRIVER_NAME "tmp102"
+
+#define	TMP102_TEMP_REG			0x00
+#define	TMP102_CONF_REG			0x01
+/* note: these bit definitions are byte swapped */
+#define		TMP102_CONF_SD		0x0100
+#define		TMP102_CONF_TM		0x0200
+#define		TMP102_CONF_POL		0x0400
+#define		TMP102_CONF_F0		0x0800
+#define		TMP102_CONF_F1		0x1000
+#define		TMP102_CONF_R0		0x2000
+#define		TMP102_CONF_R1		0x4000
+#define		TMP102_CONF_OS		0x8000
+#define		TMP102_CONF_EM		0x0010
+#define		TMP102_CONF_AL		0x0020
+#define		TMP102_CONF_CR0		0x0040
+#define		TMP102_CONF_CR1		0x0080
+#define	TMP102_TLOW_REG			0x02
+#define	TMP102_THIGH_REG		0x03
+
+struct tmp102 {
+	struct i2c_client *client;
+	struct device *hwmon_dev;
+	struct thermal_zone_device *tz;
+	struct mutex lock;
+	u16 config_orig;
+	unsigned long last_update;
+	int temp[3];
+	bool first_time;
+};
+
+/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
+static inline int tmp102_reg_to_mC(s16 val)
+{
+	return ((val & ~0x01) * 1000) / 128;
+}
+
+/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
+static inline u16 tmp102_mC_to_reg(int val)
+{
+	return (val * 128) / 1000;
+}
+
+static const u8 tmp102_reg[] = {
+	TMP102_TEMP_REG,
+	TMP102_TLOW_REG,
+	TMP102_THIGH_REG,
+};
+
+static struct tmp102 *tmp102_update_device(struct device *dev)
+{
+	struct tmp102 *tmp102 = dev_get_drvdata(dev);
+	struct i2c_client *client = tmp102->client;
+
+	mutex_lock(&tmp102->lock);
+	if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
+			int status = i2c_smbus_read_word_swapped(client,
+								 tmp102_reg[i]);
+			if (status > -1)
+				tmp102->temp[i] = tmp102_reg_to_mC(status);
+		}
+		tmp102->last_update = jiffies;
+		tmp102->first_time = false;
+	}
+	mutex_unlock(&tmp102->lock);
+	return tmp102;
+}
+
+static int tmp102_read_temp(void *dev, int *temp)
+{
+	struct tmp102 *tmp102 = tmp102_update_device(dev);
+
+	/* Is it too early even to return a conversion? */
+	if (tmp102->first_time) {
+		dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__);
+		return -EAGAIN;
+	}
+
+	*temp = tmp102->temp[0];
+
+	return 0;
+}
+
+static ssize_t tmp102_show_temp(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct tmp102 *tmp102 = tmp102_update_device(dev);
+
+	/* Is it too early even to return a read? */
+	if (tmp102->first_time)
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
+}
+
+static ssize_t tmp102_set_temp(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct tmp102 *tmp102 = dev_get_drvdata(dev);
+	struct i2c_client *client = tmp102->client;
+	long val;
+	int status;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+	val = clamp_val(val, -256000, 255000);
+
+	mutex_lock(&tmp102->lock);
+	tmp102->temp[sda->index] = val;
+	status = i2c_smbus_write_word_swapped(client, tmp102_reg[sda->index],
+					      tmp102_mC_to_reg(val));
+	mutex_unlock(&tmp102->lock);
+	return status ? : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
+			  tmp102_set_temp, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
+			  tmp102_set_temp, 2);
+
+static struct attribute *tmp102_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(tmp102);
+
+#define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
+#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
+
+static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = {
+	.get_temp = tmp102_read_temp,
+};
+
+static int tmp102_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct tmp102 *tmp102;
+	int status;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(dev,
+			"adapter doesn't support SMBus word transactions\n");
+		return -ENODEV;
+	}
+
+	tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL);
+	if (!tmp102)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, tmp102);
+	tmp102->client = client;
+
+	status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
+	if (status < 0) {
+		dev_err(dev, "error reading config register\n");
+		return status;
+	}
+	tmp102->config_orig = status;
+	status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
+					      TMP102_CONFIG);
+	if (status < 0) {
+		dev_err(dev, "error writing config register\n");
+		goto fail_restore_config;
+	}
+	status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
+	if (status < 0) {
+		dev_err(dev, "error reading config register\n");
+		goto fail_restore_config;
+	}
+	status &= ~TMP102_CONFIG_RD_ONLY;
+	if (status != TMP102_CONFIG) {
+		dev_err(dev, "config settings did not stick\n");
+		status = -ENODEV;
+		goto fail_restore_config;
+	}
+	tmp102->last_update = jiffies;
+	/* Mark that we are not ready with data until conversion is complete */
+	tmp102->first_time = true;
+	mutex_init(&tmp102->lock);
+
+	hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+						      tmp102, tmp102_groups);
+	if (IS_ERR(hwmon_dev)) {
+		dev_dbg(dev, "unable to register hwmon device\n");
+		status = PTR_ERR(hwmon_dev);
+		goto fail_restore_config;
+	}
+	tmp102->hwmon_dev = hwmon_dev;
+	tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
+						     &tmp102_of_thermal_ops);
+	if (IS_ERR(tmp102->tz))
+		tmp102->tz = NULL;
+
+	dev_info(dev, "initialized\n");
+
+	return 0;
+
+fail_restore_config:
+	i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
+				     tmp102->config_orig);
+	return status;
+}
+
+static int tmp102_remove(struct i2c_client *client)
+{
+	struct tmp102 *tmp102 = i2c_get_clientdata(client);
+
+	thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz);
+	hwmon_device_unregister(tmp102->hwmon_dev);
+
+	/* Stop monitoring if device was stopped originally */
+	if (tmp102->config_orig & TMP102_CONF_SD) {
+		int config;
+
+		config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
+		if (config >= 0)
+			i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
+						     config | TMP102_CONF_SD);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tmp102_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int config;
+
+	config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
+	if (config < 0)
+		return config;
+
+	config |= TMP102_CONF_SD;
+	return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config);
+}
+
+static int tmp102_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int config;
+
+	config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
+	if (config < 0)
+		return config;
+
+	config &= ~TMP102_CONF_SD;
+	return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config);
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume);
+
+static const struct i2c_device_id tmp102_id[] = {
+	{ "tmp102", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp102_id);
+
+static struct i2c_driver tmp102_driver = {
+	.driver.name	= DRIVER_NAME,
+	.driver.pm	= &tmp102_dev_pm_ops,
+	.probe		= tmp102_probe,
+	.remove		= tmp102_remove,
+	.id_table	= tmp102_id,
+};
+
+module_i2c_driver(tmp102_driver);
+
+MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c
new file mode 100644
index 0000000..ad571ec
--- /dev/null
+++ b/drivers/hwmon/tmp103.c
@@ -0,0 +1,199 @@
+/*
+ * Texas Instruments TMP103 SMBus temperature sensor driver
+ * Copyright (C) 2014 Heiko Schocher <hs@denx.de>
+ *
+ * Based on:
+ * Texas Instruments TMP102 SMBus temperature sensor driver
+ *
+ * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+#define TMP103_TEMP_REG		0x00
+#define TMP103_CONF_REG		0x01
+#define TMP103_TLOW_REG		0x02
+#define TMP103_THIGH_REG	0x03
+
+#define TMP103_CONF_M0		0x01
+#define TMP103_CONF_M1		0x02
+#define TMP103_CONF_LC		0x04
+#define TMP103_CONF_FL		0x08
+#define TMP103_CONF_FH		0x10
+#define TMP103_CONF_CR0		0x20
+#define TMP103_CONF_CR1		0x40
+#define TMP103_CONF_ID		0x80
+#define TMP103_CONF_SD		(TMP103_CONF_M1)
+#define TMP103_CONF_SD_MASK	(TMP103_CONF_M0 | TMP103_CONF_M1)
+
+#define TMP103_CONFIG		(TMP103_CONF_CR1 | TMP103_CONF_M1)
+#define TMP103_CONFIG_MASK	(TMP103_CONF_CR0 | TMP103_CONF_CR1 | \
+				 TMP103_CONF_M0 | TMP103_CONF_M1)
+
+static inline int tmp103_reg_to_mc(s8 val)
+{
+	return val * 1000;
+}
+
+static inline u8 tmp103_mc_to_reg(int val)
+{
+	return DIV_ROUND_CLOSEST(val, 1000);
+}
+
+static ssize_t tmp103_show_temp(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_read(regmap, sda->index, &regval);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", tmp103_reg_to_mc(regval));
+}
+
+static ssize_t tmp103_set_temp(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+	struct regmap *regmap = dev_get_drvdata(dev);
+	long val;
+	int ret;
+
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	val = clamp_val(val, -55000, 127000);
+	ret = regmap_write(regmap, sda->index, tmp103_mc_to_reg(val));
+	return ret ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp103_show_temp, NULL ,
+			  TMP103_TEMP_REG);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, tmp103_show_temp,
+			  tmp103_set_temp, TMP103_TLOW_REG);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp103_show_temp,
+			  tmp103_set_temp, TMP103_THIGH_REG);
+
+static struct attribute *tmp103_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(tmp103);
+
+static bool tmp103_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == TMP103_TEMP_REG;
+}
+
+static const struct regmap_config tmp103_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TMP103_THIGH_REG,
+	.volatile_reg = tmp103_regmap_is_volatile,
+};
+
+static int tmp103_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &tmp103_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	ret = regmap_update_bits(regmap, TMP103_CONF_REG, TMP103_CONFIG_MASK,
+				 TMP103_CONFIG);
+	if (ret < 0) {
+		dev_err(&client->dev, "error writing config register\n");
+		return ret;
+	}
+
+	i2c_set_clientdata(client, regmap);
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+						      regmap, tmp103_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+#ifdef CONFIG_PM
+static int tmp103_suspend(struct device *dev)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+
+	return regmap_update_bits(regmap, TMP103_CONF_REG,
+				  TMP103_CONF_SD_MASK, 0);
+}
+
+static int tmp103_resume(struct device *dev)
+{
+	struct regmap *regmap = dev_get_drvdata(dev);
+
+	return regmap_update_bits(regmap, TMP103_CONF_REG,
+				  TMP103_CONF_SD_MASK, TMP103_CONF_SD);
+}
+
+static const struct dev_pm_ops tmp103_dev_pm_ops = {
+	.suspend	= tmp103_suspend,
+	.resume		= tmp103_resume,
+};
+
+#define TMP103_DEV_PM_OPS (&tmp103_dev_pm_ops)
+#else
+#define	TMP103_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id tmp103_id[] = {
+	{ "tmp103", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp103_id);
+
+static struct i2c_driver tmp103_driver = {
+	.driver = {
+		.name	= "tmp103",
+		.pm	= TMP103_DEV_PM_OPS,
+	},
+	.probe		= tmp103_probe,
+	.id_table	= tmp103_id,
+};
+
+module_i2c_driver(tmp103_driver);
+
+MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
+MODULE_DESCRIPTION("Texas Instruments TMP103 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
new file mode 100644
index 0000000..ccf4cff
--- /dev/null
+++ b/drivers/hwmon/tmp401.c
@@ -0,0 +1,773 @@
+/* tmp401.c
+ *
+ * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
+ * Preliminary tmp411 support by:
+ * Gabriel Konat, Sander Leget, Wouter Willems
+ * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
+ *
+ * Cleanup and support for TMP431 and TMP432 by Guenter Roeck
+ * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC.
+ *
+ * Note this IC is in some aspect similar to the LM90, but it has quite a
+ * few differences too, for example the local temp has a higher resolution
+ * and thus has 16 bits registers for its value and limit instead of 8 bits.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bitops.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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d,
+	0x4e, 0x4f, I2C_CLIENT_END };
+
+enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 };
+
+/*
+ * The TMP401 registers, note some registers have different addresses for
+ * reading and writing
+ */
+#define TMP401_STATUS				0x02
+#define TMP401_CONFIG_READ			0x03
+#define TMP401_CONFIG_WRITE			0x09
+#define TMP401_CONVERSION_RATE_READ		0x04
+#define TMP401_CONVERSION_RATE_WRITE		0x0A
+#define TMP401_TEMP_CRIT_HYST			0x21
+#define TMP401_MANUFACTURER_ID_REG		0xFE
+#define TMP401_DEVICE_ID_REG			0xFF
+
+static const u8 TMP401_TEMP_MSB_READ[6][2] = {
+	{ 0x00, 0x01 },	/* temp */
+	{ 0x06, 0x08 },	/* low limit */
+	{ 0x05, 0x07 },	/* high limit */
+	{ 0x20, 0x19 },	/* therm (crit) limit */
+	{ 0x30, 0x34 },	/* lowest */
+	{ 0x32, 0x36 },	/* highest */
+};
+
+static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
+	{ 0, 0 },	/* temp (unused) */
+	{ 0x0C, 0x0E },	/* low limit */
+	{ 0x0B, 0x0D },	/* high limit */
+	{ 0x20, 0x19 },	/* therm (crit) limit */
+	{ 0x30, 0x34 },	/* lowest */
+	{ 0x32, 0x36 },	/* highest */
+};
+
+static const u8 TMP401_TEMP_LSB[6][2] = {
+	{ 0x15, 0x10 },	/* temp */
+	{ 0x17, 0x14 },	/* low limit */
+	{ 0x16, 0x13 },	/* high limit */
+	{ 0, 0 },	/* therm (crit) limit (unused) */
+	{ 0x31, 0x35 },	/* lowest */
+	{ 0x33, 0x37 },	/* highest */
+};
+
+static const u8 TMP432_TEMP_MSB_READ[4][3] = {
+	{ 0x00, 0x01, 0x23 },	/* temp */
+	{ 0x06, 0x08, 0x16 },	/* low limit */
+	{ 0x05, 0x07, 0x15 },	/* high limit */
+	{ 0x20, 0x19, 0x1A },	/* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_MSB_WRITE[4][3] = {
+	{ 0, 0, 0 },		/* temp  - unused */
+	{ 0x0C, 0x0E, 0x16 },	/* low limit */
+	{ 0x0B, 0x0D, 0x15 },	/* high limit */
+	{ 0x20, 0x19, 0x1A },	/* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_LSB[3][3] = {
+	{ 0x29, 0x10, 0x24 },	/* temp */
+	{ 0x3E, 0x14, 0x18 },	/* low limit */
+	{ 0x3D, 0x13, 0x17 },	/* high limit */
+};
+
+/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
+static const u8 TMP432_STATUS_REG[] = {
+	0x1b, 0x36, 0x35, 0x37 };
+
+/* Flags */
+#define TMP401_CONFIG_RANGE			BIT(2)
+#define TMP401_CONFIG_SHUTDOWN			BIT(6)
+#define TMP401_STATUS_LOCAL_CRIT		BIT(0)
+#define TMP401_STATUS_REMOTE_CRIT		BIT(1)
+#define TMP401_STATUS_REMOTE_OPEN		BIT(2)
+#define TMP401_STATUS_REMOTE_LOW		BIT(3)
+#define TMP401_STATUS_REMOTE_HIGH		BIT(4)
+#define TMP401_STATUS_LOCAL_LOW			BIT(5)
+#define TMP401_STATUS_LOCAL_HIGH		BIT(6)
+
+/* On TMP432, each status has its own register */
+#define TMP432_STATUS_LOCAL			BIT(0)
+#define TMP432_STATUS_REMOTE1			BIT(1)
+#define TMP432_STATUS_REMOTE2			BIT(2)
+
+/* Manufacturer / Device ID's */
+#define TMP401_MANUFACTURER_ID			0x55
+#define TMP401_DEVICE_ID			0x11
+#define TMP411A_DEVICE_ID			0x12
+#define TMP411B_DEVICE_ID			0x13
+#define TMP411C_DEVICE_ID			0x10
+#define TMP431_DEVICE_ID			0x31
+#define TMP432_DEVICE_ID			0x32
+#define TMP435_DEVICE_ID			0x35
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id tmp401_id[] = {
+	{ "tmp401", tmp401 },
+	{ "tmp411", tmp411 },
+	{ "tmp431", tmp431 },
+	{ "tmp432", tmp432 },
+	{ "tmp435", tmp435 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp401_id);
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct tmp401_data {
+	struct i2c_client *client;
+	const struct attribute_group *groups[3];
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+	enum chips kind;
+
+	unsigned int update_interval;	/* in milliseconds */
+
+	/* register values */
+	u8 status[4];
+	u8 config;
+	u16 temp[6][3];
+	u8 temp_crit_hyst;
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static int tmp401_register_to_temp(u16 reg, u8 config)
+{
+	int temp = reg;
+
+	if (config & TMP401_CONFIG_RANGE)
+		temp -= 64 * 256;
+
+	return DIV_ROUND_CLOSEST(temp * 125, 32);
+}
+
+static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
+{
+	if (config & TMP401_CONFIG_RANGE) {
+		temp = clamp_val(temp, -64000, 191000);
+		temp += 64000;
+	} else
+		temp = clamp_val(temp, 0, 127000);
+
+	return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
+}
+
+static int tmp401_update_device_reg16(struct i2c_client *client,
+				      struct tmp401_data *data)
+{
+	int i, j, val;
+	int num_regs = data->kind == tmp411 ? 6 : 4;
+	int num_sensors = data->kind == tmp432 ? 3 : 2;
+
+	for (i = 0; i < num_sensors; i++) {		/* local / r1 / r2 */
+		for (j = 0; j < num_regs; j++) {	/* temp / low / ... */
+			u8 regaddr;
+			/*
+			 * High byte must be read first immediately followed
+			 * by the low byte
+			 */
+			regaddr = data->kind == tmp432 ?
+						TMP432_TEMP_MSB_READ[j][i] :
+						TMP401_TEMP_MSB_READ[j][i];
+			val = i2c_smbus_read_byte_data(client, regaddr);
+			if (val < 0)
+				return val;
+			data->temp[j][i] = val << 8;
+			if (j == 3)		/* crit is msb only */
+				continue;
+			regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i]
+						       : TMP401_TEMP_LSB[j][i];
+			val = i2c_smbus_read_byte_data(client, regaddr);
+			if (val < 0)
+				return val;
+			data->temp[j][i] |= val;
+		}
+	}
+	return 0;
+}
+
+static struct tmp401_data *tmp401_update_device(struct device *dev)
+{
+	struct tmp401_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	struct tmp401_data *ret = data;
+	int i, val;
+	unsigned long next_update;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated +
+		      msecs_to_jiffies(data->update_interval);
+	if (time_after(jiffies, next_update) || !data->valid) {
+		if (data->kind != tmp432) {
+			/*
+			 * The driver uses the TMP432 status format internally.
+			 * Convert status to TMP432 format for other chips.
+			 */
+			val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+			if (val < 0) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->status[0] =
+			  (val & TMP401_STATUS_REMOTE_OPEN) >> 1;
+			data->status[1] =
+			  ((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
+			  ((val & TMP401_STATUS_LOCAL_LOW) >> 5);
+			data->status[2] =
+			  ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
+			  ((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
+			data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
+						| TMP401_STATUS_REMOTE_CRIT);
+		} else {
+			for (i = 0; i < ARRAY_SIZE(data->status); i++) {
+				val = i2c_smbus_read_byte_data(client,
+							TMP432_STATUS_REG[i]);
+				if (val < 0) {
+					ret = ERR_PTR(val);
+					goto abort;
+				}
+				data->status[i] = val;
+			}
+		}
+
+		val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+		if (val < 0) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->config = val;
+		val = tmp401_update_device_reg16(client, data);
+		if (val < 0) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
+		if (val < 0) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp_crit_hyst = val;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct tmp401_data *data = tmp401_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n",
+		tmp401_register_to_temp(data->temp[nr][index], data->config));
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int temp, index = to_sensor_dev_attr(devattr)->index;
+	struct tmp401_data *data = tmp401_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	mutex_lock(&data->update_lock);
+	temp = tmp401_register_to_temp(data->temp[3][index], data->config);
+	temp -= data->temp_crit_hyst * 1000;
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_status(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int mask = to_sensor_dev_attr_2(devattr)->index;
+	struct tmp401_data *data = tmp401_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", !!(data->status[nr] & mask));
+}
+
+static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct tmp401_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	u16 reg;
+	u8 regaddr;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
+
+	mutex_lock(&data->update_lock);
+
+	regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index]
+				       : TMP401_TEMP_MSB_WRITE[nr][index];
+	i2c_smbus_write_byte_data(client, regaddr, reg >> 8);
+	if (nr != 3) {
+		regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index]
+					       : TMP401_TEMP_LSB[nr][index];
+		i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF);
+	}
+	data->temp[nr][index] = reg;
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
+	*devattr, const char *buf, size_t count)
+{
+	int temp, index = to_sensor_dev_attr(devattr)->index;
+	struct tmp401_data *data = tmp401_update_device(dev);
+	long val;
+	u8 reg;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	if (data->config & TMP401_CONFIG_RANGE)
+		val = clamp_val(val, -64000, 191000);
+	else
+		val = clamp_val(val, 0, 127000);
+
+	mutex_lock(&data->update_lock);
+	temp = tmp401_register_to_temp(data->temp[3][index], data->config);
+	val = clamp_val(val, temp - 255000, temp);
+	reg = ((temp - val) + 500) / 1000;
+
+	i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST,
+				  reg);
+
+	data->temp_crit_hyst = reg;
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Resets the historical measurements of minimum and maximum temperatures.
+ * This is done by writing any value to any of the minimum/maximum registers
+ * (0x30-0x37).
+ */
+static ssize_t reset_temp_history(struct device *dev,
+	struct device_attribute	*devattr, const char *buf, size_t count)
+{
+	struct tmp401_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	if (val != 1) {
+		dev_err(dev,
+			"temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
+			val);
+		return -EINVAL;
+	}
+	mutex_lock(&data->update_lock);
+	i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct tmp401_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct tmp401_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err, rate;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/*
+	 * For valid rates, interval can be calculated as
+	 *	interval = (1 << (7 - rate)) * 125;
+	 * Rounded rate is therefore
+	 *	rate = 7 - __fls(interval * 4 / (125 * 3));
+	 * Use clamp_val() to avoid overflows, and to ensure valid input
+	 * for __fls.
+	 */
+	val = clamp_val(val, 125, 16000);
+	rate = 7 - __fls(val * 4 / (125 * 3));
+	mutex_lock(&data->update_lock);
+	i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
+	data->update_interval = (1 << (7 - rate)) * 125;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 3, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_crit_hyst, store_temp_crit_hyst, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL,
+			    1, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL,
+			    2, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL,
+			    3, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 3, 1);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+			  NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL,
+			    0, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL,
+			    1, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL,
+			    2, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL,
+			    3, TMP432_STATUS_REMOTE1);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+		   set_update_interval);
+
+static struct attribute *tmp401_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+
+	&dev_attr_update_interval.attr,
+
+	NULL
+};
+
+static const struct attribute_group tmp401_group = {
+	.attrs = tmp401_attributes,
+};
+
+/*
+ * Additional features of the TMP411 chip.
+ * The TMP411 stores the minimum and maximum
+ * temperature measured since power-on, chip-reset, or
+ * minimum and maximum register reset for both the local
+ * and remote channels.
+ */
+static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
+static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
+			  0);
+
+static struct attribute *tmp411_attributes[] = {
+	&sensor_dev_attr_temp1_highest.dev_attr.attr,
+	&sensor_dev_attr_temp1_lowest.dev_attr.attr,
+	&sensor_dev_attr_temp2_highest.dev_attr.attr,
+	&sensor_dev_attr_temp2_lowest.dev_attr.attr,
+	&sensor_dev_attr_temp_reset_history.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group tmp411_group = {
+	.attrs = tmp411_attributes,
+};
+
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+			    store_temp, 3, 2);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+			  NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL,
+			    0, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL,
+			    1, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL,
+			    2, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL,
+			    3, TMP432_STATUS_REMOTE2);
+
+static struct attribute *tmp432_attributes[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+
+	NULL
+};
+
+static const struct attribute_group tmp432_group = {
+	.attrs = tmp432_attributes,
+};
+
+/*
+ * Begin non sysfs callback code (aka Real code)
+ */
+
+static int tmp401_init_client(struct tmp401_data *data,
+			      struct i2c_client *client)
+{
+	int config, config_orig, status = 0;
+
+	/* Set the conversion rate to 2 Hz */
+	i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+	data->update_interval = 500;
+
+	/* Start conversions (disable shutdown if necessary) */
+	config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+	if (config < 0)
+		return config;
+
+	config_orig = config;
+	config &= ~TMP401_CONFIG_SHUTDOWN;
+
+	if (config != config_orig)
+		status = i2c_smbus_write_byte_data(client,
+						   TMP401_CONFIG_WRITE,
+						   config);
+
+	return status;
+}
+
+static int tmp401_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	enum chips kind;
+	struct i2c_adapter *adapter = client->adapter;
+	u8 reg;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Detect and identify the chip */
+	reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG);
+	if (reg != TMP401_MANUFACTURER_ID)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG);
+
+	switch (reg) {
+	case TMP401_DEVICE_ID:
+		if (client->addr != 0x4c)
+			return -ENODEV;
+		kind = tmp401;
+		break;
+	case TMP411A_DEVICE_ID:
+		if (client->addr != 0x4c)
+			return -ENODEV;
+		kind = tmp411;
+		break;
+	case TMP411B_DEVICE_ID:
+		if (client->addr != 0x4d)
+			return -ENODEV;
+		kind = tmp411;
+		break;
+	case TMP411C_DEVICE_ID:
+		if (client->addr != 0x4e)
+			return -ENODEV;
+		kind = tmp411;
+		break;
+	case TMP431_DEVICE_ID:
+		if (client->addr != 0x4c && client->addr != 0x4d)
+			return -ENODEV;
+		kind = tmp431;
+		break;
+	case TMP432_DEVICE_ID:
+		if (client->addr != 0x4c && client->addr != 0x4d)
+			return -ENODEV;
+		kind = tmp432;
+		break;
+	case TMP435_DEVICE_ID:
+		kind = tmp435;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+	if (reg & 0x1b)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ);
+	/* Datasheet says: 0x1-0x6 */
+	if (reg > 15)
+		return -ENODEV;
+
+	strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int tmp401_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	static const char * const names[] = {
+		"TMP401", "TMP411", "TMP431", "TMP432", "TMP435"
+	};
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct tmp401_data *data;
+	int groups = 0, status;
+
+	data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+	data->kind = id->driver_data;
+
+	/* Initialize the TMP401 chip */
+	status = tmp401_init_client(data, client);
+	if (status < 0)
+		return status;
+
+	/* Register sysfs hooks */
+	data->groups[groups++] = &tmp401_group;
+
+	/* Register additional tmp411 sysfs hooks */
+	if (data->kind == tmp411)
+		data->groups[groups++] = &tmp411_group;
+
+	/* Register additional tmp432 sysfs hooks */
+	if (data->kind == tmp432)
+		data->groups[groups++] = &tmp432_group;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, data->groups);
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
+
+	return 0;
+}
+
+static struct i2c_driver tmp401_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "tmp401",
+	},
+	.probe		= tmp401_probe,
+	.id_table	= tmp401_id,
+	.detect		= tmp401_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(tmp401_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
new file mode 100644
index 0000000..85d48d8
--- /dev/null
+++ b/drivers/hwmon/tmp421.c
@@ -0,0 +1,332 @@
+/* tmp421.c
+ *
+ * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
+ * Preliminary support by:
+ * Melvin Rook, Raymond Ng
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the Texas Instruments TMP421 SMBus temperature sensor IC.
+ * Supported models: TMP421, TMP422, TMP423, TMP441, TMP442
+ */
+
+#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>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
+					     I2C_CLIENT_END };
+
+enum chips { tmp421, tmp422, tmp423, tmp441, tmp442 };
+
+/* The TMP421 registers */
+#define TMP421_STATUS_REG			0x08
+#define TMP421_CONFIG_REG_1			0x09
+#define TMP421_CONVERSION_RATE_REG		0x0B
+#define TMP421_MANUFACTURER_ID_REG		0xFE
+#define TMP421_DEVICE_ID_REG			0xFF
+
+static const u8 TMP421_TEMP_MSB[4]		= { 0x00, 0x01, 0x02, 0x03 };
+static const u8 TMP421_TEMP_LSB[4]		= { 0x10, 0x11, 0x12, 0x13 };
+
+/* Flags */
+#define TMP421_CONFIG_SHUTDOWN			0x40
+#define TMP421_CONFIG_RANGE			0x04
+
+/* Manufacturer / Device ID's */
+#define TMP421_MANUFACTURER_ID			0x55
+#define TMP421_DEVICE_ID			0x21
+#define TMP422_DEVICE_ID			0x22
+#define TMP423_DEVICE_ID			0x23
+#define TMP441_DEVICE_ID			0x41
+#define TMP442_DEVICE_ID			0x42
+
+static const struct i2c_device_id tmp421_id[] = {
+	{ "tmp421", 2 },
+	{ "tmp422", 3 },
+	{ "tmp423", 4 },
+	{ "tmp441", 2 },
+	{ "tmp442", 3 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp421_id);
+
+struct tmp421_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;
+	unsigned long last_updated;
+	int channels;
+	u8 config;
+	s16 temp[4];
+};
+
+static int temp_from_s16(s16 reg)
+{
+	/* Mask out status bits */
+	int temp = reg & ~0xf;
+
+	return (temp * 1000 + 128) / 256;
+}
+
+static int temp_from_u16(u16 reg)
+{
+	/* Mask out status bits */
+	int temp = reg & ~0xf;
+
+	/* Add offset for extended temperature range. */
+	temp -= 64 * 256;
+
+	return (temp * 1000 + 128) / 256;
+}
+
+static struct tmp421_data *tmp421_update_device(struct device *dev)
+{
+	struct tmp421_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+		data->config = i2c_smbus_read_byte_data(client,
+			TMP421_CONFIG_REG_1);
+
+		for (i = 0; i < data->channels; i++) {
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+				TMP421_TEMP_MSB[i]) << 8;
+			data->temp[i] |= i2c_smbus_read_byte_data(client,
+				TMP421_TEMP_LSB[i]);
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static ssize_t show_temp_value(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct tmp421_data *data = tmp421_update_device(dev);
+	int temp;
+
+	mutex_lock(&data->update_lock);
+	if (data->config & TMP421_CONFIG_RANGE)
+		temp = temp_from_u16(data->temp[index]);
+	else
+		temp = temp_from_s16(data->temp[index]);
+	mutex_unlock(&data->update_lock);
+
+	return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_fault(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct tmp421_data *data = tmp421_update_device(dev);
+
+	/*
+	 * The OPEN bit signals a fault. This is bit 0 of the temperature
+	 * register (low byte).
+	 */
+	if (data->temp[index] & 0x01)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static umode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a,
+				int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct tmp421_data *data = dev_get_drvdata(dev);
+	struct device_attribute *devattr;
+	unsigned int index;
+
+	devattr = container_of(a, struct device_attribute, attr);
+	index = to_sensor_dev_attr(devattr)->index;
+
+	if (index < data->channels)
+		return a->mode;
+
+	return 0;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
+
+static struct attribute *tmp421_attr[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group tmp421_group = {
+	.attrs = tmp421_attr,
+	.is_visible = tmp421_is_visible,
+};
+
+static const struct attribute_group *tmp421_groups[] = {
+	&tmp421_group,
+	NULL
+};
+
+static int tmp421_init_client(struct i2c_client *client)
+{
+	int config, config_orig;
+
+	/* Set the conversion rate to 2 Hz */
+	i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05);
+
+	/* Start conversions (disable shutdown if necessary) */
+	config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
+	if (config < 0) {
+		dev_err(&client->dev,
+			"Could not read configuration register (%d)\n", config);
+		return config;
+	}
+
+	config_orig = config;
+	config &= ~TMP421_CONFIG_SHUTDOWN;
+
+	if (config != config_orig) {
+		dev_info(&client->dev, "Enable monitoring chip\n");
+		i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config);
+	}
+
+	return 0;
+}
+
+static int tmp421_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	enum chips kind;
+	struct i2c_adapter *adapter = client->adapter;
+	const char * const names[] = { "TMP421", "TMP422", "TMP423",
+				       "TMP441", "TMP442" };
+	int addr = client->addr;
+	u8 reg;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP421_MANUFACTURER_ID_REG);
+	if (reg != TMP421_MANUFACTURER_ID)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP421_CONVERSION_RATE_REG);
+	if (reg & 0xf8)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP421_STATUS_REG);
+	if (reg & 0x7f)
+		return -ENODEV;
+
+	reg = i2c_smbus_read_byte_data(client, TMP421_DEVICE_ID_REG);
+	switch (reg) {
+	case TMP421_DEVICE_ID:
+		kind = tmp421;
+		break;
+	case TMP422_DEVICE_ID:
+		if (addr == 0x2a)
+			return -ENODEV;
+		kind = tmp422;
+		break;
+	case TMP423_DEVICE_ID:
+		if (addr != 0x4c && addr != 0x4d)
+			return -ENODEV;
+		kind = tmp423;
+		break;
+	case TMP441_DEVICE_ID:
+		kind = tmp441;
+		break;
+	case TMP442_DEVICE_ID:
+		if (addr != 0x4c && addr != 0x4d)
+			return -ENODEV;
+		kind = tmp442;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE);
+	dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
+		 names[kind], client->addr);
+
+	return 0;
+}
+
+static int tmp421_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device *hwmon_dev;
+	struct tmp421_data *data;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->update_lock);
+	data->channels = id->driver_data;
+	data->client = client;
+
+	err = tmp421_init_client(client);
+	if (err)
+		return err;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data, tmp421_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct i2c_driver tmp421_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "tmp421",
+	},
+	.probe = tmp421_probe,
+	.id_table = tmp421_id,
+	.detect = tmp421_detect,
+	.address_list = normal_i2c,
+};
+
+module_i2c_driver(tmp421_driver);
+
+MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
+MODULE_DESCRIPTION("Texas Instruments TMP421/422/423/441/442 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c
new file mode 100644
index 0000000..b5caf7f
--- /dev/null
+++ b/drivers/hwmon/twl4030-madc-hwmon.c
@@ -0,0 +1,118 @@
+/*
+ *
+ * TWL4030 MADC Hwmon driver-This driver monitors the real time
+ * conversion of analog signals like battery temperature,
+ * battery type, battery level etc. User can ask for the conversion on a
+ * particular channel using the sysfs nodes.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * 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.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c/twl.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/stddef.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <linux/types.h>
+
+/*
+ * sysfs hook function
+ */
+static ssize_t madc_read(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct twl4030_madc_request req = {
+		.channels = 1 << attr->index,
+		.method = TWL4030_MADC_SW2,
+		.type = TWL4030_MADC_WAIT,
+	};
+	long val;
+
+	val = twl4030_madc_conversion(&req);
+	if (val < 0)
+		return val;
+
+	return sprintf(buf, "%d\n", req.rbuf[attr->index]);
+}
+
+/* sysfs nodes to read individual channels from user side */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, madc_read, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, madc_read, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, madc_read, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, madc_read, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, madc_read, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, madc_read, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, madc_read, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, madc_read, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, madc_read, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, madc_read, NULL, 9);
+static SENSOR_DEVICE_ATTR(curr10_input, S_IRUGO, madc_read, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15);
+
+static struct attribute *twl4030_madc_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_curr10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(twl4030_madc);
+
+static int twl4030_madc_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *hwmon;
+
+	hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
+						       "twl4030_madc", NULL,
+						       twl4030_madc_groups);
+	return PTR_ERR_OR_ZERO(hwmon);
+}
+
+static struct platform_driver twl4030_madc_hwmon_driver = {
+	.probe = twl4030_madc_hwmon_probe,
+	.driver = {
+		   .name = "twl4030_madc_hwmon",
+		   },
+};
+
+module_platform_driver(twl4030_madc_hwmon_driver);
+
+MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("J Keerthy");
+MODULE_ALIAS("platform:twl4030_madc_hwmon");
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644
index 0000000..f2816c7
--- /dev/null
+++ b/drivers/hwmon/ultra45_env.c
@@ -0,0 +1,323 @@
+/*
+ * ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+#define DRV_MODULE_VERSION	"0.1"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* PIC device registers */
+#define REG_CMD		0x00UL
+#define  REG_CMD_RESET	0x80
+#define  REG_CMD_ESTAR	0x01
+#define REG_STAT	0x01UL
+#define  REG_STAT_FWVER	0xf0
+#define  REG_STAT_TGOOD	0x08
+#define  REG_STAT_STALE	0x04
+#define  REG_STAT_BUSY	0x02
+#define  REG_STAT_FAULT	0x01
+#define REG_DATA	0x40UL
+#define REG_ADDR	0x41UL
+#define REG_SIZE	0x42UL
+
+/* Registers accessed indirectly via REG_DATA/REG_ADDR */
+#define IREG_FAN0		0x00
+#define IREG_FAN1		0x01
+#define IREG_FAN2		0x02
+#define IREG_FAN3		0x03
+#define IREG_FAN4		0x04
+#define IREG_FAN5		0x05
+#define IREG_LCL_TEMP		0x06
+#define IREG_RMT1_TEMP		0x07
+#define IREG_RMT2_TEMP		0x08
+#define IREG_RMT3_TEMP		0x09
+#define IREG_LM95221_TEMP	0x0a
+#define IREG_FIRE_TEMP		0x0b
+#define IREG_LSI1064_TEMP	0x0c
+#define IREG_FRONT_TEMP		0x0d
+#define IREG_FAN_STAT		0x0e
+#define IREG_VCORE0		0x0f
+#define IREG_VCORE1		0x10
+#define IREG_VMEM0		0x11
+#define IREG_VMEM1		0x12
+#define IREG_PSU_TEMP		0x13
+
+struct env {
+	void __iomem	*regs;
+	spinlock_t	lock;
+
+	struct device	*hwmon_dev;
+};
+
+static u8 env_read(struct env *p, u8 ireg)
+{
+	u8 ret;
+
+	spin_lock(&p->lock);
+	writeb(ireg, p->regs + REG_ADDR);
+	ret = readb(p->regs + REG_DATA);
+	spin_unlock(&p->lock);
+
+	return ret;
+}
+
+static void env_write(struct env *p, u8 ireg, u8 val)
+{
+	spin_lock(&p->lock);
+	writeb(ireg, p->regs + REG_ADDR);
+	writeb(val, p->regs + REG_DATA);
+	spin_unlock(&p->lock);
+}
+
+/*
+ * There seems to be a adr7462 providing these values, thus a lot
+ * of these calculations are borrowed from the adt7470 driver.
+ */
+#define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID	(0xff << 8)
+#define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	int rpm, period;
+	u8 val;
+
+	val = env_read(p, IREG_FAN0 + fan_nr);
+	period = (int) val << 8;
+	if (FAN_DATA_VALID(period))
+		rpm = FAN_PERIOD_TO_RPM(period);
+	else
+		rpm = 0;
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	unsigned long rpm;
+	struct env *p = dev_get_drvdata(dev);
+	int period;
+	u8 val;
+	int err;
+
+	err = kstrtoul(buf, 10, &rpm);
+	if (err)
+		return err;
+
+	if (!rpm)
+		return -EINVAL;
+
+	period = FAN_RPM_TO_PERIOD(rpm);
+	val = period >> 8;
+	env_write(p, IREG_FAN0 + fan_nr, val);
+
+	return count;
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	u8 val = env_read(p, IREG_FAN_STAT);
+	return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
+}
+
+#define fan(index)							\
+static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,	\
+		show_fan_speed, set_fan_speed, index);			\
+static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO,			\
+		show_fan_fault, NULL, index)
+
+fan(0);
+fan(1);
+fan(2);
+fan(3);
+fan(4);
+
+static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	int temp_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	s8 val;
+
+	val = env_read(p, IREG_LCL_TEMP + temp_nr);
+	return sprintf(buf, "%d\n", ((int) val) - 64);
+}
+
+static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
+
+static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	u8 val;
+
+	val = readb(p->regs + REG_STAT);
+	return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
+static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
+static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
+static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL,
+			  3);
+
+static ssize_t show_fwver(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct env *p = dev_get_drvdata(dev);
+	u8 val;
+
+	val = readb(p->regs + REG_STAT);
+	return sprintf(buf, "%d\n", val >> 4);
+}
+
+static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	return sprintf(buf, "ultra45\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *env_attributes[] = {
+	&sensor_dev_attr_fan0_speed.dev_attr.attr,
+	&sensor_dev_attr_fan0_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_speed.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan2_speed.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan3_speed.dev_attr.attr,
+	&sensor_dev_attr_fan3_fault.dev_attr.attr,
+	&sensor_dev_attr_fan4_speed.dev_attr.attr,
+	&sensor_dev_attr_fan4_fault.dev_attr.attr,
+	&sensor_dev_attr_psu_fan_fault.dev_attr.attr,
+	&sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
+	&sensor_dev_attr_cpu0_temp.dev_attr.attr,
+	&sensor_dev_attr_cpu1_temp.dev_attr.attr,
+	&sensor_dev_attr_motherboard_temp.dev_attr.attr,
+	&sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
+	&sensor_dev_attr_fire_temp.dev_attr.attr,
+	&sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
+	&sensor_dev_attr_front_panel_temp.dev_attr.attr,
+	&sensor_dev_attr_psu_temp.dev_attr.attr,
+	&sensor_dev_attr_fan_failure.dev_attr.attr,
+	&sensor_dev_attr_env_bus_busy.dev_attr.attr,
+	&sensor_dev_attr_env_data_stale.dev_attr.attr,
+	&sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
+	&sensor_dev_attr_firmware_version.dev_attr.attr,
+	&sensor_dev_attr_name.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group env_group = {
+	.attrs = env_attributes,
+};
+
+static int env_probe(struct platform_device *op)
+{
+	struct env *p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
+	int err = -ENOMEM;
+
+	if (!p)
+		goto out;
+
+	spin_lock_init(&p->lock);
+
+	p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
+	if (!p->regs)
+		goto out;
+
+	err = sysfs_create_group(&op->dev.kobj, &env_group);
+	if (err)
+		goto out_iounmap;
+
+	p->hwmon_dev = hwmon_device_register(&op->dev);
+	if (IS_ERR(p->hwmon_dev)) {
+		err = PTR_ERR(p->hwmon_dev);
+		goto out_sysfs_remove_group;
+	}
+
+	platform_set_drvdata(op, p);
+	err = 0;
+
+out:
+	return err;
+
+out_sysfs_remove_group:
+	sysfs_remove_group(&op->dev.kobj, &env_group);
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+
+	goto out;
+}
+
+static int env_remove(struct platform_device *op)
+{
+	struct env *p = platform_get_drvdata(op);
+
+	if (p) {
+		sysfs_remove_group(&op->dev.kobj, &env_group);
+		hwmon_device_unregister(p->hwmon_dev);
+		of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id env_match[] = {
+	{
+		.name = "env-monitor",
+		.compatible = "SUNW,ebus-pic16f747-env",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, env_match);
+
+static struct platform_driver env_driver = {
+	.driver = {
+		.name = "ultra45_env",
+		.of_match_table = env_match,
+	},
+	.probe		= env_probe,
+	.remove		= env_remove,
+};
+
+module_platform_driver(env_driver);
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
new file mode 100644
index 0000000..8ba419d
--- /dev/null
+++ b/drivers/hwmon/vexpress.c
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#define DRVNAME "vexpress-hwmon"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/vexpress.h>
+
+struct vexpress_hwmon_data {
+	struct device *hwmon_dev;
+	struct regmap *reg;
+};
+
+static ssize_t vexpress_hwmon_label_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	const char *label = of_get_property(dev->of_node, "label", NULL);
+
+	return snprintf(buffer, PAGE_SIZE, "%s\n", label);
+}
+
+static ssize_t vexpress_hwmon_u32_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
+	int err;
+	u32 value;
+
+	err = regmap_read(data->reg, 0, &value);
+	if (err)
+		return err;
+
+	return snprintf(buffer, PAGE_SIZE, "%u\n", value /
+			to_sensor_dev_attr(dev_attr)->index);
+}
+
+static ssize_t vexpress_hwmon_u64_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
+	int err;
+	u32 value_hi, value_lo;
+
+	err = regmap_read(data->reg, 0, &value_lo);
+	if (err)
+		return err;
+
+	err = regmap_read(data->reg, 1, &value_hi);
+	if (err)
+		return err;
+
+	return snprintf(buffer, PAGE_SIZE, "%llu\n",
+			div_u64(((u64)value_hi << 32) | value_lo,
+			to_sensor_dev_attr(dev_attr)->index));
+}
+
+static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj,
+		struct attribute *attr, int index)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct device_attribute *dev_attr = container_of(attr,
+				struct device_attribute, attr);
+
+	if (dev_attr->show == vexpress_hwmon_label_show &&
+			!of_get_property(dev->of_node, "label", NULL))
+		return 0;
+
+	return attr->mode;
+}
+
+struct vexpress_hwmon_type {
+	const char *name;
+	const struct attribute_group **attr_groups;
+};
+
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show,
+		NULL, 1000);
+static struct attribute *vexpress_hwmon_attrs_volt[] = {
+	&dev_attr_in1_label.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	NULL
+};
+static struct attribute_group vexpress_hwmon_group_volt = {
+	.is_visible = vexpress_hwmon_attr_is_visible,
+	.attrs = vexpress_hwmon_attrs_volt,
+};
+static struct vexpress_hwmon_type vexpress_hwmon_volt = {
+	.name = "vexpress_volt",
+	.attr_groups = (const struct attribute_group *[]) {
+		&vexpress_hwmon_group_volt,
+		NULL,
+	},
+};
+#endif
+
+static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show,
+		NULL, 1000);
+static struct attribute *vexpress_hwmon_attrs_amp[] = {
+	&dev_attr_curr1_label.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	NULL
+};
+static struct attribute_group vexpress_hwmon_group_amp = {
+	.is_visible = vexpress_hwmon_attr_is_visible,
+	.attrs = vexpress_hwmon_attrs_amp,
+};
+static struct vexpress_hwmon_type vexpress_hwmon_amp = {
+	.name = "vexpress_amp",
+	.attr_groups = (const struct attribute_group *[]) {
+		&vexpress_hwmon_group_amp,
+		NULL
+	},
+};
+
+static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show,
+		NULL, 1000);
+static struct attribute *vexpress_hwmon_attrs_temp[] = {
+	&dev_attr_temp1_label.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+static struct attribute_group vexpress_hwmon_group_temp = {
+	.is_visible = vexpress_hwmon_attr_is_visible,
+	.attrs = vexpress_hwmon_attrs_temp,
+};
+static struct vexpress_hwmon_type vexpress_hwmon_temp = {
+	.name = "vexpress_temp",
+	.attr_groups = (const struct attribute_group *[]) {
+		&vexpress_hwmon_group_temp,
+		NULL
+	},
+};
+
+static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show,
+		NULL, 1);
+static struct attribute *vexpress_hwmon_attrs_power[] = {
+	&dev_attr_power1_label.attr,
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	NULL
+};
+static struct attribute_group vexpress_hwmon_group_power = {
+	.is_visible = vexpress_hwmon_attr_is_visible,
+	.attrs = vexpress_hwmon_attrs_power,
+};
+static struct vexpress_hwmon_type vexpress_hwmon_power = {
+	.name = "vexpress_power",
+	.attr_groups = (const struct attribute_group *[]) {
+		&vexpress_hwmon_group_power,
+		NULL
+	},
+};
+
+static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show,
+		NULL, 1);
+static struct attribute *vexpress_hwmon_attrs_energy[] = {
+	&dev_attr_energy1_label.attr,
+	&sensor_dev_attr_energy1_input.dev_attr.attr,
+	NULL
+};
+static struct attribute_group vexpress_hwmon_group_energy = {
+	.is_visible = vexpress_hwmon_attr_is_visible,
+	.attrs = vexpress_hwmon_attrs_energy,
+};
+static struct vexpress_hwmon_type vexpress_hwmon_energy = {
+	.name = "vexpress_energy",
+	.attr_groups = (const struct attribute_group *[]) {
+		&vexpress_hwmon_group_energy,
+		NULL
+	},
+};
+
+static const struct of_device_id vexpress_hwmon_of_match[] = {
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+	{
+		.compatible = "arm,vexpress-volt",
+		.data = &vexpress_hwmon_volt,
+	},
+#endif
+	{
+		.compatible = "arm,vexpress-amp",
+		.data = &vexpress_hwmon_amp,
+	}, {
+		.compatible = "arm,vexpress-temp",
+		.data = &vexpress_hwmon_temp,
+	}, {
+		.compatible = "arm,vexpress-power",
+		.data = &vexpress_hwmon_power,
+	}, {
+		.compatible = "arm,vexpress-energy",
+		.data = &vexpress_hwmon_energy,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
+
+static int vexpress_hwmon_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	struct vexpress_hwmon_data *data;
+	const struct vexpress_hwmon_type *type;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, data);
+
+	match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
+	if (!match)
+		return -ENODEV;
+	type = match->data;
+
+	data->reg = devm_regmap_init_vexpress_config(&pdev->dev);
+	if (IS_ERR(data->reg))
+		return PTR_ERR(data->reg);
+
+	data->hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+			type->name, data, type->attr_groups);
+
+	return PTR_ERR_OR_ZERO(data->hwmon_dev);
+}
+
+static struct platform_driver vexpress_hwmon_driver = {
+	.probe = vexpress_hwmon_probe,
+	.driver	= {
+		.name = DRVNAME,
+		.of_match_table = vexpress_hwmon_of_match,
+	},
+};
+
+module_platform_driver(vexpress_hwmon_driver);
+
+MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
+MODULE_DESCRIPTION("Versatile Express hwmon sensors driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vexpress-hwmon");
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
new file mode 100644
index 0000000..ac91c07
--- /dev/null
+++ b/drivers/hwmon/via-cputemp.c
@@ -0,0 +1,381 @@
+/*
+ * via-cputemp.c - Driver for VIA CPU core temperature monitoring
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ *
+ * based on existing coretemp.c, which is
+ *
+ * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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/hwmon.h>
+#include <linux/hwmon-vid.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/cpu_device_id.h>
+
+#define DRVNAME	"via_cputemp"
+
+enum { SHOW_TEMP, SHOW_LABEL, SHOW_NAME };
+
+/*
+ * Functions declaration
+ */
+
+struct via_cputemp_data {
+	struct device *hwmon_dev;
+	const char *name;
+	u8 vrm;
+	u32 id;
+	u32 msr_temp;
+	u32 msr_vid;
+};
+
+/*
+ * 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 via_cputemp_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->id);
+	return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	struct via_cputemp_data *data = dev_get_drvdata(dev);
+	u32 eax, edx;
+	int err;
+
+	err = rdmsr_safe_on_cpu(data->id, data->msr_temp, &eax, &edx);
+	if (err)
+		return -EAGAIN;
+
+	return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000);
+}
+
+static ssize_t show_cpu_vid(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	struct via_cputemp_data *data = dev_get_drvdata(dev);
+	u32 eax, edx;
+	int err;
+
+	err = rdmsr_safe_on_cpu(data->id, data->msr_vid, &eax, &edx);
+	if (err)
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", vid_from_reg(~edx & 0x7f, data->vrm));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
+			  SHOW_TEMP);
+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 *via_cputemp_attributes[] = {
+	&sensor_dev_attr_name.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group via_cputemp_group = {
+	.attrs = via_cputemp_attributes,
+};
+
+/* Optional attributes */
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_cpu_vid, NULL);
+
+static int via_cputemp_probe(struct platform_device *pdev)
+{
+	struct via_cputemp_data *data;
+	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+	int err;
+	u32 eax, edx;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->id = pdev->id;
+	data->name = "via_cputemp";
+
+	switch (c->x86_model) {
+	case 0xA:
+		/* C7 A */
+	case 0xD:
+		/* C7 D */
+		data->msr_temp = 0x1169;
+		data->msr_vid = 0x198;
+		break;
+	case 0xF:
+		/* Nano */
+		data->msr_temp = 0x1423;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	/* test if we can access the TEMPERATURE MSR */
+	err = rdmsr_safe_on_cpu(data->id, data->msr_temp, &eax, &edx);
+	if (err) {
+		dev_err(&pdev->dev,
+			"Unable to access TEMPERATURE MSR, giving up\n");
+		return err;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
+	if (err)
+		return err;
+
+	if (data->msr_vid)
+		data->vrm = vid_which_vrm();
+
+	if (data->vrm) {
+		err = device_create_file(&pdev->dev, &dev_attr_cpu0_vid);
+		if (err)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		dev_err(&pdev->dev, "Class registration failed (%d)\n",
+			err);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	if (data->vrm)
+		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
+	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
+	return err;
+}
+
+static int via_cputemp_remove(struct platform_device *pdev)
+{
+	struct via_cputemp_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	if (data->vrm)
+		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
+	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
+	return 0;
+}
+
+static struct platform_driver via_cputemp_driver = {
+	.driver = {
+		.name = DRVNAME,
+	},
+	.probe = via_cputemp_probe,
+	.remove = via_cputemp_remove,
+};
+
+struct pdev_entry {
+	struct list_head list;
+	struct platform_device *pdev;
+	unsigned int cpu;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static int via_cputemp_device_add(unsigned int cpu)
+{
+	int err;
+	struct platform_device *pdev;
+	struct pdev_entry *pdev_entry;
+
+	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;
+	}
+
+	pdev_entry->pdev = pdev;
+	pdev_entry->cpu = cpu;
+	mutex_lock(&pdev_list_mutex);
+	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:
+	return err;
+}
+
+static void via_cputemp_device_remove(unsigned int cpu)
+{
+	struct pdev_entry *p;
+
+	mutex_lock(&pdev_list_mutex);
+	list_for_each_entry(p, &pdev_list, list) {
+		if (p->cpu == cpu) {
+			platform_device_unregister(p->pdev);
+			list_del(&p->list);
+			mutex_unlock(&pdev_list_mutex);
+			kfree(p);
+			return;
+		}
+	}
+	mutex_unlock(&pdev_list_mutex);
+}
+
+static int via_cputemp_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:
+		via_cputemp_device_add(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		via_cputemp_device_remove(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block via_cputemp_cpu_notifier __refdata = {
+	.notifier_call = via_cputemp_cpu_callback,
+};
+
+static const struct x86_cpu_id __initconst cputemp_ids[] = {
+	{ X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
+	{ X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
+	{ X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
+
+static int __init via_cputemp_init(void)
+{
+	int i, err;
+
+	if (!x86_match_cpu(cputemp_ids))
+		return -ENODEV;
+
+	err = platform_driver_register(&via_cputemp_driver);
+	if (err)
+		goto exit;
+
+	cpu_notifier_register_begin();
+	for_each_online_cpu(i) {
+		struct cpuinfo_x86 *c = &cpu_data(i);
+
+		if (c->x86 != 6)
+			continue;
+
+		if (c->x86_model < 0x0a)
+			continue;
+
+		if (c->x86_model > 0x0f) {
+			pr_warn("Unknown CPU model 0x%x\n", c->x86_model);
+			continue;
+		}
+
+		via_cputemp_device_add(i);
+	}
+
+#ifndef CONFIG_HOTPLUG_CPU
+	if (list_empty(&pdev_list)) {
+		cpu_notifier_register_done();
+		err = -ENODEV;
+		goto exit_driver_unreg;
+	}
+#endif
+
+	__register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+	cpu_notifier_register_done();
+	return 0;
+
+#ifndef CONFIG_HOTPLUG_CPU
+exit_driver_unreg:
+	platform_driver_unregister(&via_cputemp_driver);
+#endif
+exit:
+	return err;
+}
+
+static void __exit via_cputemp_exit(void)
+{
+	struct pdev_entry *p, *n;
+
+	cpu_notifier_register_begin();
+	__unregister_hotcpu_notifier(&via_cputemp_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);
+	cpu_notifier_register_done();
+	platform_driver_unregister(&via_cputemp_driver);
+}
+
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("VIA CPU temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(via_cputemp_init)
+module_exit(via_cputemp_exit)
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
new file mode 100644
index 0000000..40dd93c
--- /dev/null
+++ b/drivers/hwmon/via686a.c
@@ -0,0 +1,964 @@
+/*
+ * via686a.c - Part of lm_sensors, Linux kernel modules
+ *	       for hardware monitoring
+ *
+ * Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
+ *			      Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ *			      Mark Studebaker <mdsxyz123@yahoo.com>,
+ *			      and Bob Dougherty <bobd@stanford.edu>
+ *
+ * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
+ * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
+ *
+ * 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.
+ */
+
+/*
+ * Supports the Via VT82C686A, VT82C686B south bridges.
+ * Reports all as a 686A.
+ * Warning - only supports a single device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/*
+ * If force_addr is set to anything different from 0, we forcibly enable
+ * the device at the given address.
+ */
+static unsigned short force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+
+static struct platform_device *pdev;
+
+/*
+ * The Via 686a southbridge has a LM78-like chip integrated on the same IC.
+ * This driver is a customized copy of lm78.c
+ */
+
+/* Many VIA686A constants specified below */
+
+/* Length of ISA address segment */
+#define VIA686A_EXTENT		0x80
+#define VIA686A_BASE_REG	0x70
+#define VIA686A_ENABLE_REG	0x74
+
+/* The VIA686A registers */
+/* ins numbered 0-4 */
+#define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
+#define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
+#define VIA686A_REG_IN(nr)	(0x22 + (nr))
+
+/* fans numbered 1-2 */
+#define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
+#define VIA686A_REG_FAN(nr)	(0x28 + (nr))
+
+/* temps numbered 1-3 */
+static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
+static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
+static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
+/* bits 7-6 */
+#define VIA686A_REG_TEMP_LOW1	0x4b
+/* 2 = bits 5-4, 3 = bits 7-6 */
+#define VIA686A_REG_TEMP_LOW23	0x49
+
+#define VIA686A_REG_ALARM1	0x41
+#define VIA686A_REG_ALARM2	0x42
+#define VIA686A_REG_FANDIV	0x47
+#define VIA686A_REG_CONFIG	0x40
+/*
+ * The following register sets temp interrupt mode (bits 1-0 for temp1,
+ * 3-2 for temp2, 5-4 for temp3).  Modes are:
+ * 00 interrupt stays as long as value is out-of-range
+ * 01 interrupt is cleared once register is read (default)
+ * 10 comparator mode- like 00, but ignores hysteresis
+ * 11 same as 00
+ */
+#define VIA686A_REG_TEMP_MODE		0x4b
+/* We'll just assume that you want to set all 3 simultaneously: */
+#define VIA686A_TEMP_MODE_MASK		0x3F
+#define VIA686A_TEMP_MODE_CONTINUOUS	0x00
+
+/*
+ * Conversions. Limit checking is only done on the TO_REG
+ * variants.
+ *
+ ******** VOLTAGE CONVERSIONS (Bob Dougherty) ********
+ * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
+ * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
+ * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
+ * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
+ * voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
+ * voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
+ * in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
+ * That is:
+ * volts = (25*regVal+133)*factor
+ * regVal = (volts/factor-133)/25
+ * (These conversions were contributed by Jonathan Teh Soon Yew
+ * <j.teh@iname.com>)
+ */
+static inline u8 IN_TO_REG(long val, int in_num)
+{
+	/*
+	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
+	 * Rounding is done (120500 is actually 133000 - 12500).
+	 * Remember that val is expressed in 0.001V/bit, which is why we divide
+	 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
+	 * for the constants.
+	 */
+	if (in_num <= 1)
+		return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
+	else if (in_num == 2)
+		return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
+	else if (in_num == 3)
+		return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
+	else
+		return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
+				      255);
+}
+
+static inline long IN_FROM_REG(u8 val, int in_num)
+{
+	/*
+	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
+	 * We also multiply them by 1000 because we want 0.001V/bit for the
+	 * output value. Rounding is done.
+	 */
+	if (in_num <= 1)
+		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
+	else if (in_num == 2)
+		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
+	else if (in_num == 3)
+		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
+	else
+		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
+}
+
+/********* FAN RPM CONVERSIONS ********/
+/*
+ * Higher register values = slower fans (the fan's strobe gates a counter).
+ * But this chip saturates back at 0, not at 255 like all the other chips.
+ * So, 0 means 0 RPM
+ */
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 0;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
+}
+
+#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
+				((val) * (div)))
+
+/******** TEMP CONVERSIONS (Bob Dougherty) *********/
+/*
+ * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
+ *	if(temp<169)
+ *		return double(temp)*0.427-32.08;
+ *	else if(temp>=169 && temp<=202)
+ *		return double(temp)*0.582-58.16;
+ *	else
+ *		return double(temp)*0.924-127.33;
+ *
+ * A fifth-order polynomial fits the unofficial data (provided by Alex van
+ * Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
+ * numbers on my machine (ie. they agree with what my BIOS tells me).
+ * Here's the fifth-order fit to the 8-bit data:
+ * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
+ *	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
+ *
+ * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
+ * finding my typos in this formula!)
+ *
+ * Alas, none of the elegant function-fit solutions will work because we
+ * aren't allowed to use floating point in the kernel and doing it with
+ * integers doesn't provide enough precision.  So we'll do boring old
+ * look-up table stuff.  The unofficial data (see below) have effectively
+ * 7-bit resolution (they are rounded to the nearest degree).  I'm assuming
+ * that the transfer function of the device is monotonic and smooth, so a
+ * smooth function fit to the data will allow us to get better precision.
+ * I used the 5th-order poly fit described above and solved for
+ * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
+ * precision.  (I could have done all 1024 values for our 10-bit readings,
+ * but the function is very linear in the useful range (0-80 deg C), so
+ * we'll just use linear interpolation for 10-bit readings.)  So, temp_lut
+ * is the temp at via register values 0-255:
+ */
+static const s16 temp_lut[] = {
+	-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
+	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
+	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
+	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
+	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
+	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
+	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
+	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
+	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
+	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
+	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
+	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
+	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
+	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
+	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
+	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
+	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
+	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
+	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
+	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
+	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
+	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
+};
+
+/*
+ * the original LUT values from Alex van Kaam <darkside@chello.nl>
+ * (for via register values 12-240):
+ * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
+ * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
+ * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
+ * -3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12,
+ * 12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22,
+ * 22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33,
+ * 33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,
+ * 45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60,
+ * 61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,
+ * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
+ *
+ *
+ * Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
+ * an extra term for a good fit to these inverse data!) and then
+ * solving for each temp value from -50 to 110 (the useable range for
+ * this chip).  Here's the fit:
+ * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
+ * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
+ * Note that n=161:
+ */
+static const u8 via_lut[] = {
+	12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
+	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
+	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
+	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
+	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
+	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
+	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
+	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
+	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
+	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
+	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+	239, 240
+};
+
+/*
+ * Converting temps to (8-bit) hyst and over registers
+ * No interpolation here.
+ * The +50 is because the temps start at -50
+ */
+static inline u8 TEMP_TO_REG(long val)
+{
+	return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
+		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
+}
+
+/* for 8-bit temperature hyst and over registers */
+#define TEMP_FROM_REG(val)	((long)temp_lut[val] * 100)
+
+/* for 10-bit temperature readings */
+static inline long TEMP_FROM_REG10(u16 val)
+{
+	u16 eight_bits = val >> 2;
+	u16 two_bits = val & 3;
+
+	/* no interpolation for these */
+	if (two_bits == 0 || eight_bits == 255)
+		return TEMP_FROM_REG(eight_bits);
+
+	/* do some linear interpolation */
+	return (temp_lut[eight_bits] * (4 - two_bits) +
+		temp_lut[eight_bits + 1] * two_bits) * 25;
+}
+
+#define DIV_FROM_REG(val) (1 << (val))
+#define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
+
+/*
+ * For each registered chip, we need to keep some data in memory.
+ * The structure is dynamically allocated.
+ */
+struct via686a_data {
+	unsigned short addr;
+	const char *name;
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[5];		/* Register value */
+	u8 in_max[5];		/* Register value */
+	u8 in_min[5];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	u16 temp[3];		/* Register value 10 bit */
+	u8 temp_over[3];	/* Register value */
+	u8 temp_hyst[3];	/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
+
+static int via686a_probe(struct platform_device *pdev);
+static int via686a_remove(struct platform_device *pdev);
+
+static inline int via686a_read_value(struct via686a_data *data, u8 reg)
+{
+	return inb_p(data->addr + reg);
+}
+
+static inline void via686a_write_value(struct via686a_data *data, u8 reg,
+				       u8 value)
+{
+	outb_p(value, data->addr + reg);
+}
+
+static struct via686a_data *via686a_update_device(struct device *dev);
+static void via686a_init_device(struct via686a_data *data);
+
+/* following are the sysfs callback functions */
+
+/* 7 voltage sensors */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val, nr);
+	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
+			data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val, nr);
+	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
+			data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#define show_in_offset(offset)					\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
+
+show_in_offset(0);
+show_in_offset(1);
+show_in_offset(2);
+show_in_offset(3);
+show_in_offset(4);
+
+/* 3 temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
+}
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
+}
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
+}
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_over[nr] = TEMP_TO_REG(val);
+	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
+			    data->temp_over[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_hyst[nr] = TEMP_TO_REG(val);
+	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
+			    data->temp_hyst[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#define show_temp_offset(offset)					\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+		show_temp, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_over, set_temp_over, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp_hyst, set_temp_hyst, offset - 1);
+
+show_temp_offset(1);
+show_temp_offset(2);
+show_temp_offset(3);
+
+/* 2 Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+				DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n",
+		FAN_FROM_REG(data->fan_min[nr],
+			     DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+		char *buf) {
+	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
+	int old;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	old = via686a_read_value(data, VIA686A_REG_FANDIV);
+	data->fan_div[nr] = DIV_TO_REG(val);
+	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
+	via686a_write_value(data, VIA686A_REG_FANDIV, old);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define show_fan_offset(offset)						\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);
+
+show_fan_offset(1);
+show_fan_offset(2);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct via686a_data *data = via686a_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct via686a_data *data = via686a_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct via686a_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *via686a_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&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_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_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+
+	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group via686a_group = {
+	.attrs = via686a_attributes,
+};
+
+static struct platform_driver via686a_driver = {
+	.driver = {
+		.name	= "via686a",
+	},
+	.probe		= via686a_probe,
+	.remove		= via686a_remove,
+};
+
+
+/* This is called when the module is loaded */
+static int via686a_probe(struct platform_device *pdev)
+{
+	struct via686a_data *data;
+	struct resource *res;
+	int err;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
+				 via686a_driver.driver.name)) {
+		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start, (unsigned long)res->end);
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, data);
+	data->addr = res->start;
+	data->name = "via686a";
+	mutex_init(&data->update_lock);
+
+	/* Initialize the VIA686A chip */
+	via686a_init_device(data);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
+	if (err)
+		return err;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->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(&pdev->dev.kobj, &via686a_group);
+	return err;
+}
+
+static int via686a_remove(struct platform_device *pdev)
+{
+	struct via686a_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
+
+	return 0;
+}
+
+static void via686a_update_fan_div(struct via686a_data *data)
+{
+	int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
+	data->fan_div[0] = (reg >> 4) & 0x03;
+	data->fan_div[1] = reg >> 6;
+}
+
+static void via686a_init_device(struct via686a_data *data)
+{
+	u8 reg;
+
+	/* Start monitoring */
+	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
+	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
+
+	/* Configure temp interrupt mode for continuous-interrupt operation */
+	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
+	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
+			    (reg & ~VIA686A_TEMP_MODE_MASK)
+			    | VIA686A_TEMP_MODE_CONTINUOUS);
+
+	/* Pre-read fan clock divisor values */
+	via686a_update_fan_div(data);
+}
+
+static struct via686a_data *via686a_update_device(struct device *dev)
+{
+	struct via686a_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		for (i = 0; i <= 4; i++) {
+			data->in[i] =
+			    via686a_read_value(data, VIA686A_REG_IN(i));
+			data->in_min[i] = via686a_read_value(data,
+							     VIA686A_REG_IN_MIN
+							     (i));
+			data->in_max[i] =
+			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
+		}
+		for (i = 1; i <= 2; i++) {
+			data->fan[i - 1] =
+			    via686a_read_value(data, VIA686A_REG_FAN(i));
+			data->fan_min[i - 1] = via686a_read_value(data,
+						     VIA686A_REG_FAN_MIN(i));
+		}
+		for (i = 0; i <= 2; i++) {
+			data->temp[i] = via686a_read_value(data,
+						 VIA686A_REG_TEMP[i]) << 2;
+			data->temp_over[i] =
+			    via686a_read_value(data,
+					       VIA686A_REG_TEMP_OVER[i]);
+			data->temp_hyst[i] =
+			    via686a_read_value(data,
+					       VIA686A_REG_TEMP_HYST[i]);
+		}
+		/*
+		 * add in lower 2 bits
+		 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
+		 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
+		 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
+		 */
+		data->temp[0] |= (via686a_read_value(data,
+						     VIA686A_REG_TEMP_LOW1)
+				  & 0xc0) >> 6;
+		data->temp[1] |=
+		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
+		     0x30) >> 4;
+		data->temp[2] |=
+		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
+		     0xc0) >> 6;
+
+		via686a_update_fan_div(data);
+		data->alarms =
+		    via686a_read_value(data,
+				       VIA686A_REG_ALARM1) |
+		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static const struct pci_device_id via686a_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
+
+static int via686a_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + VIA686A_EXTENT - 1,
+		.name	= "via686a",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc("via686a", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int via686a_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	u16 address, val;
+
+	if (force_addr) {
+		address = force_addr & ~(VIA686A_EXTENT - 1);
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+			return -ENODEV;
+	}
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
+		return -ENODEV;
+
+	address = val & ~(VIA686A_EXTENT - 1);
+	if (address == 0) {
+		dev_err(&dev->dev,
+			"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+		return -ENODEV;
+	if (!(val & 0x0001)) {
+		if (!force_addr) {
+			dev_warn(&dev->dev,
+				 "Sensors disabled, enable with force_addr=0x%x\n",
+				 address);
+			return -ENODEV;
+		}
+
+		dev_warn(&dev->dev, "Enabling sensors\n");
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
+					  val | 0x0001))
+			return -ENODEV;
+	}
+
+	if (platform_driver_register(&via686a_driver))
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	if (via686a_device_add(address))
+		goto exit_unregister;
+
+	/*
+	 * Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+	s_bridge = pci_dev_get(dev);
+	return -ENODEV;
+
+exit_unregister:
+	platform_driver_unregister(&via686a_driver);
+exit:
+	return -ENODEV;
+}
+
+static struct pci_driver via686a_pci_driver = {
+	.name		= "via686a",
+	.id_table	= via686a_pci_ids,
+	.probe		= via686a_pci_probe,
+};
+
+static int __init sm_via686a_init(void)
+{
+	return pci_register_driver(&via686a_pci_driver);
+}
+
+static void __exit sm_via686a_exit(void)
+{
+	pci_unregister_driver(&via686a_pci_driver);
+	if (s_bridge != NULL) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&via686a_driver);
+		pci_dev_put(s_bridge);
+		s_bridge = NULL;
+	}
+}
+
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
+	      "Mark Studebaker <mdsxyz123@yahoo.com> "
+	      "and Bob Dougherty <bobd@stanford.edu>");
+MODULE_DESCRIPTION("VIA 686A Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(sm_via686a_init);
+module_exit(sm_via686a_exit);
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
new file mode 100644
index 0000000..3a6bfa5
--- /dev/null
+++ b/drivers/hwmon/vt1211.c
@@ -0,0 +1,1371 @@
+/*
+ * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware
+ *            monitoring features
+ * Copyright (C) 2006 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker
+ * and its port to kernel 2.6 by Lars Ekman.
+ *
+ * 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.
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static int uch_config = -1;
+module_param(uch_config, int, 0);
+MODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration");
+
+static int int_mode = -1;
+module_param(int_mode, int, 0);
+MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "vt1211"
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows.
+ *
+ * Sensor          Voltage Mode   Temp Mode   Notes (from the datasheet)
+ * --------        ------------   ---------   --------------------------
+ * Reading 1                      temp1       Intel thermal diode
+ * Reading 3                      temp2       Internal thermal diode
+ * UCH1/Reading2   in0            temp3       NTC type thermistor
+ * UCH2            in1            temp4       +2.5V
+ * UCH3            in2            temp5       VccP
+ * UCH4            in3            temp6       +5V
+ * UCH5            in4            temp7       +12V
+ * 3.3V            in5                        Internal VDD (+3.3V)
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-5 (ix) */
+#define VT1211_REG_IN(ix)		(0x21 + (ix))
+#define VT1211_REG_IN_MIN(ix)		((ix) == 0 ? 0x3e : 0x2a + 2 * (ix))
+#define VT1211_REG_IN_MAX(ix)		((ix) == 0 ? 0x3d : 0x29 + 2 * (ix))
+
+/* Temperatures (temp) numbered 0-6 (ix) */
+static u8 regtemp[]	= {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
+static u8 regtempmax[]	= {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31};
+static u8 regtemphyst[]	= {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32};
+
+/* Fans numbered 0-1 (ix) */
+#define VT1211_REG_FAN(ix)		(0x29 + (ix))
+#define VT1211_REG_FAN_MIN(ix)		(0x3b + (ix))
+#define VT1211_REG_FAN_DIV		 0x47
+
+/* PWMs numbered 0-1 (ix) */
+/* Auto points numbered 0-3 (ap) */
+#define VT1211_REG_PWM(ix)		(0x60 + (ix))
+#define VT1211_REG_PWM_CLK		 0x50
+#define VT1211_REG_PWM_CTL		 0x51
+#define VT1211_REG_PWM_AUTO_TEMP(ap)	(0x55 - (ap))
+#define VT1211_REG_PWM_AUTO_PWM(ix, ap)	(0x58 + 2 * (ix) - (ap))
+
+/* Miscellaneous registers */
+#define VT1211_REG_CONFIG		0x40
+#define VT1211_REG_ALARM1		0x41
+#define VT1211_REG_ALARM2		0x42
+#define VT1211_REG_VID			0x45
+#define VT1211_REG_UCH_CONFIG		0x4a
+#define VT1211_REG_TEMP1_CONFIG		0x4b
+#define VT1211_REG_TEMP2_CONFIG		0x4c
+
+/* In, temp & fan alarm bits */
+static const u8 bitalarmin[]	= {11, 0, 1, 3, 8, 2, 9};
+static const u8 bitalarmtemp[]	= {4, 15, 11, 0, 1, 3, 8};
+static const u8 bitalarmfan[]	= {6, 7};
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct vt1211_data {
+	unsigned short addr;
+	const char *name;
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* Register values */
+	u8  in[6];
+	u8  in_max[6];
+	u8  in_min[6];
+	u8  temp[7];
+	u8  temp_max[7];
+	u8  temp_hyst[7];
+	u8  fan[2];
+	u8  fan_min[2];
+	u8  fan_div[2];
+	u8  fan_ctl;
+	u8  pwm[2];
+	u8  pwm_ctl[2];
+	u8  pwm_clk;
+	u8  pwm_auto_temp[4];
+	u8  pwm_auto_pwm[2][4];
+	u8  vid;		/* Read once at init time */
+	u8  vrm;
+	u8  uch_config;		/* Read once at init time */
+	u16 alarms;
+};
+
+/* ix = [0-5] */
+#define ISVOLT(ix, uch_config)	((ix) > 4 ? 1 : \
+				 !(((uch_config) >> ((ix) + 2)) & 1))
+
+/* ix = [0-6] */
+#define ISTEMP(ix, uch_config)	((ix) < 2 ? 1 : \
+				 ((uch_config) >> (ix)) & 1)
+
+/*
+ * in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
+ * driver according to the VT1211 BIOS porting guide
+ */
+#define IN_FROM_REG(ix, reg)	((reg) < 3 ? 0 : (ix) == 5 ? \
+				 (((reg) - 3) * 15882 + 479) / 958 : \
+				 (((reg) - 3) * 10000 + 479) / 958)
+#define IN_TO_REG(ix, val)	(clamp_val((ix) == 5 ? \
+				 ((val) * 958 + 7941) / 15882 + 3 : \
+				 ((val) * 958 + 5000) / 10000 + 3, 0, 255))
+
+/*
+ * temp1 (ix = 0) is an intel thermal diode which is scaled in user space.
+ * temp2 (ix = 1) is the internal temp diode so it's scaled in the driver
+ * according to some measurements that I took on an EPIA M10000.
+ * temp3-7 are thermistor based so the driver returns the voltage measured at
+ * the pin (range 0V - 2.2V).
+ */
+#define TEMP_FROM_REG(ix, reg)	((ix) == 0 ? (reg) * 1000 : \
+				 (ix) == 1 ? (reg) < 51 ? 0 : \
+				 ((reg) - 51) * 1000 : \
+				 ((253 - (reg)) * 2200 + 105) / 210)
+#define TEMP_TO_REG(ix, val)	clamp_val( \
+				 ((ix) == 0 ? ((val) + 500) / 1000 : \
+				  (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
+				  253 - ((val) * 210 + 1100) / 2200), 0, 255)
+
+#define DIV_FROM_REG(reg)	(1 << (reg))
+
+#define RPM_FROM_REG(reg, div)	(((reg) == 0) || ((reg) == 255) ? 0 : \
+				 1310720 / (reg) / DIV_FROM_REG(div))
+#define RPM_TO_REG(val, div)	((val) == 0 ? 255 : \
+				 clamp_val((1310720 / (val) / \
+				 DIV_FROM_REG(div)), 1, 254))
+
+/* ---------------------------------------------------------------------
+ * Super-I/O constants and functions
+ * --------------------------------------------------------------------- */
+
+/*
+ * Configuration index port registers
+ * The vt1211 can live at 2 different addresses so we need to probe both
+ */
+#define SIO_REG_CIP1		0x2e
+#define SIO_REG_CIP2		0x4e
+
+/* Configuration registers */
+#define SIO_VT1211_LDN		0x07	/* logical device number */
+#define SIO_VT1211_DEVID	0x20	/* device ID */
+#define SIO_VT1211_DEVREV	0x21	/* device revision */
+#define SIO_VT1211_ACTIVE	0x30	/* HW monitor active */
+#define SIO_VT1211_BADDR	0x60	/* base I/O address */
+#define SIO_VT1211_ID		0x3c	/* VT1211 device ID */
+
+/* VT1211 logical device numbers */
+#define SIO_VT1211_LDN_HWMON	0x0b	/* HW monitor */
+
+static inline void superio_outb(int sio_cip, int reg, int val)
+{
+	outb(reg, sio_cip);
+	outb(val, sio_cip + 1);
+}
+
+static inline int superio_inb(int sio_cip, int reg)
+{
+	outb(reg, sio_cip);
+	return inb(sio_cip + 1);
+}
+
+static inline void superio_select(int sio_cip, int ldn)
+{
+	outb(SIO_VT1211_LDN, sio_cip);
+	outb(ldn, sio_cip + 1);
+}
+
+static inline void superio_enter(int sio_cip)
+{
+	outb(0x87, sio_cip);
+	outb(0x87, sio_cip);
+}
+
+static inline void superio_exit(int sio_cip)
+{
+	outb(0xaa, sio_cip);
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static inline u8 vt1211_read8(struct vt1211_data *data, u8 reg)
+{
+	return inb(data->addr + reg);
+}
+
+static inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val)
+{
+	outb(val, data->addr + reg);
+}
+
+static struct vt1211_data *vt1211_update_device(struct device *dev)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	int ix, val;
+
+	mutex_lock(&data->update_lock);
+
+	/* registers cache is refreshed after 1 second */
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		/* read VID */
+		data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f;
+
+		/* voltage (in) registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+			if (ISVOLT(ix, data->uch_config)) {
+				data->in[ix] = vt1211_read8(data,
+						VT1211_REG_IN(ix));
+				data->in_min[ix] = vt1211_read8(data,
+						VT1211_REG_IN_MIN(ix));
+				data->in_max[ix] = vt1211_read8(data,
+						VT1211_REG_IN_MAX(ix));
+			}
+		}
+
+		/* temp registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+			if (ISTEMP(ix, data->uch_config)) {
+				data->temp[ix] = vt1211_read8(data,
+						regtemp[ix]);
+				data->temp_max[ix] = vt1211_read8(data,
+						regtempmax[ix]);
+				data->temp_hyst[ix] = vt1211_read8(data,
+						regtemphyst[ix]);
+			}
+		}
+
+		/* fan & pwm registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+			data->fan[ix] = vt1211_read8(data,
+						VT1211_REG_FAN(ix));
+			data->fan_min[ix] = vt1211_read8(data,
+						VT1211_REG_FAN_MIN(ix));
+			data->pwm[ix] = vt1211_read8(data,
+						VT1211_REG_PWM(ix));
+		}
+		val = vt1211_read8(data, VT1211_REG_FAN_DIV);
+		data->fan_div[0] = (val >> 4) & 3;
+		data->fan_div[1] = (val >> 6) & 3;
+		data->fan_ctl = val & 0xf;
+
+		val = vt1211_read8(data, VT1211_REG_PWM_CTL);
+		data->pwm_ctl[0] = val & 0xf;
+		data->pwm_ctl[1] = (val >> 4) & 0xf;
+
+		data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK);
+
+		/* pwm & temp auto point registers */
+		data->pwm_auto_pwm[0][1] = vt1211_read8(data,
+						VT1211_REG_PWM_AUTO_PWM(0, 1));
+		data->pwm_auto_pwm[0][2] = vt1211_read8(data,
+						VT1211_REG_PWM_AUTO_PWM(0, 2));
+		data->pwm_auto_pwm[1][1] = vt1211_read8(data,
+						VT1211_REG_PWM_AUTO_PWM(1, 1));
+		data->pwm_auto_pwm[1][2] = vt1211_read8(data,
+						VT1211_REG_PWM_AUTO_PWM(1, 2));
+		for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) {
+			data->pwm_auto_temp[ix] = vt1211_read8(data,
+						VT1211_REG_PWM_AUTO_TEMP(ix));
+		}
+
+		/* alarm registers */
+		data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) |
+				vt1211_read8(data, VT1211_REG_ALARM1);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs interfaces
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_IN_INPUT	0
+#define SHOW_SET_IN_MIN	1
+#define SHOW_SET_IN_MAX	2
+#define SHOW_IN_ALARM	3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SHOW_IN_INPUT:
+		res = IN_FROM_REG(ix, data->in[ix]);
+		break;
+	case SHOW_SET_IN_MIN:
+		res = IN_FROM_REG(ix, data->in_min[ix]);
+		break;
+	case SHOW_SET_IN_MAX:
+		res = IN_FROM_REG(ix, data->in_max[ix]);
+		break;
+	case SHOW_IN_ALARM:
+		res = (data->alarms >> bitalarmin[ix]) & 1;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SHOW_SET_IN_MIN:
+		data->in_min[ix] = IN_TO_REG(ix, val);
+		vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]);
+		break;
+	case SHOW_SET_IN_MAX:
+		data->in_max[ix] = IN_TO_REG(ix, val);
+		vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs interfaces
+ * ix = [0-6]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_TEMP_INPUT		0
+#define SHOW_SET_TEMP_MAX	1
+#define SHOW_SET_TEMP_MAX_HYST	2
+#define SHOW_TEMP_ALARM		3
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SHOW_TEMP_INPUT:
+		res = TEMP_FROM_REG(ix, data->temp[ix]);
+		break;
+	case SHOW_SET_TEMP_MAX:
+		res = TEMP_FROM_REG(ix, data->temp_max[ix]);
+		break;
+	case SHOW_SET_TEMP_MAX_HYST:
+		res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
+		break;
+	case SHOW_TEMP_ALARM:
+		res = (data->alarms >> bitalarmtemp[ix]) & 1;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SHOW_SET_TEMP_MAX:
+		data->temp_max[ix] = TEMP_TO_REG(ix, val);
+		vt1211_write8(data, regtempmax[ix],
+			      data->temp_max[ix]);
+		break;
+	case SHOW_SET_TEMP_MAX_HYST:
+		data->temp_hyst[ix] = TEMP_TO_REG(ix, val);
+		vt1211_write8(data, regtemphyst[ix],
+			      data->temp_hyst[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_FAN_INPUT		0
+#define SHOW_SET_FAN_MIN	1
+#define SHOW_SET_FAN_DIV	2
+#define SHOW_FAN_ALARM		3
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SHOW_FAN_INPUT:
+		res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
+		break;
+	case SHOW_SET_FAN_MIN:
+		res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
+		break;
+	case SHOW_SET_FAN_DIV:
+		res = DIV_FROM_REG(data->fan_div[ix]);
+		break;
+	case SHOW_FAN_ALARM:
+		res = (data->alarms >> bitalarmfan[ix]) & 1;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	/* sync the data cache */
+	reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+	data->fan_div[0] = (reg >> 4) & 3;
+	data->fan_div[1] = (reg >> 6) & 3;
+	data->fan_ctl = reg & 0xf;
+
+	switch (fn) {
+	case SHOW_SET_FAN_MIN:
+		data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]);
+		vt1211_write8(data, VT1211_REG_FAN_MIN(ix),
+			      data->fan_min[ix]);
+		break;
+	case SHOW_SET_FAN_DIV:
+		switch (val) {
+		case 1:
+			data->fan_div[ix] = 0;
+			break;
+		case 2:
+			data->fan_div[ix] = 1;
+			break;
+		case 4:
+			data->fan_div[ix] = 2;
+			break;
+		case 8:
+			data->fan_div[ix] = 3;
+			break;
+		default:
+			count = -EINVAL;
+			dev_warn(dev,
+				 "fan div value %ld not supported. Choose one of 1, 2, 4, or 8.\n",
+				 val);
+			goto EXIT;
+		}
+		vt1211_write8(data, VT1211_REG_FAN_DIV,
+			      ((data->fan_div[1] << 6) |
+			       (data->fan_div[0] << 4) |
+				data->fan_ctl));
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_PWM			0
+#define SHOW_SET_PWM_ENABLE		1
+#define SHOW_SET_PWM_FREQ		2
+#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP	3
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SHOW_PWM:
+		res = data->pwm[ix];
+		break;
+	case SHOW_SET_PWM_ENABLE:
+		res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0;
+		break;
+	case SHOW_SET_PWM_FREQ:
+		res = 90000 >> (data->pwm_clk & 7);
+		break;
+	case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+		res = (data->pwm_ctl[ix] & 7) + 1;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int tmp, reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	switch (fn) {
+	case SHOW_SET_PWM_ENABLE:
+		/* sync the data cache */
+		reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+		data->fan_div[0] = (reg >> 4) & 3;
+		data->fan_div[1] = (reg >> 6) & 3;
+		data->fan_ctl = reg & 0xf;
+		reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+		data->pwm_ctl[0] = reg & 0xf;
+		data->pwm_ctl[1] = (reg >> 4) & 0xf;
+		switch (val) {
+		case 0:
+			data->pwm_ctl[ix] &= 7;
+			/*
+			 * disable SmartGuardian if both PWM outputs are
+			 * disabled
+			 */
+			if ((data->pwm_ctl[ix ^ 1] & 1) == 0)
+				data->fan_ctl &= 0xe;
+			break;
+		case 2:
+			data->pwm_ctl[ix] |= 8;
+			data->fan_ctl |= 1;
+			break;
+		default:
+			count = -EINVAL;
+			dev_warn(dev,
+				 "pwm mode %ld not supported. Choose one of 0 or 2.\n",
+				 val);
+			goto EXIT;
+		}
+		vt1211_write8(data, VT1211_REG_PWM_CTL,
+			      ((data->pwm_ctl[1] << 4) |
+				data->pwm_ctl[0]));
+		vt1211_write8(data, VT1211_REG_FAN_DIV,
+			      ((data->fan_div[1] << 6) |
+			       (data->fan_div[0] << 4) |
+				data->fan_ctl));
+		break;
+	case SHOW_SET_PWM_FREQ:
+		val = 135000 / clamp_val(val, 135000 >> 7, 135000);
+		/* calculate tmp = log2(val) */
+		tmp = 0;
+		for (val >>= 1; val > 0; val >>= 1)
+			tmp++;
+		/* sync the data cache */
+		reg = vt1211_read8(data, VT1211_REG_PWM_CLK);
+		data->pwm_clk = (reg & 0xf8) | tmp;
+		vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk);
+		break;
+	case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+		if (val < 1 || val > 7) {
+			count = -EINVAL;
+			dev_warn(dev,
+				 "temp channel %ld not supported. Choose a value between 1 and 7.\n",
+				 val);
+			goto EXIT;
+		}
+		if (!ISTEMP(val - 1, data->uch_config)) {
+			count = -EINVAL;
+			dev_warn(dev, "temp channel %ld is not available.\n",
+				 val);
+			goto EXIT;
+		}
+		/* sync the data cache */
+		reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+		data->pwm_ctl[0] = reg & 0xf;
+		data->pwm_ctl[1] = (reg >> 4) & 0xf;
+		data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1);
+		vt1211_write8(data, VT1211_REG_PWM_CTL,
+			      ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0]));
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM auto point definitions
+ * ix = [0-1]
+ * ap = [0-3]
+ * --------------------------------------------------------------------- */
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_temp mapping table:
+ * Note that there is only a single set of temp auto points that controls both
+ * PWM controllers. We still create 2 sets of sysfs files to make it look
+ * more consistent even though they map to the same registers.
+ *
+ * ix ap : description
+ * -------------------
+ * 0  0  : pwm1/2 off temperature        (pwm_auto_temp[0])
+ * 0  1  : pwm1/2 low speed temperature  (pwm_auto_temp[1])
+ * 0  2  : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 0  3  : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ * 1  0  : pwm1/2 off temperature        (pwm_auto_temp[0])
+ * 1  1  : pwm1/2 low speed temperature  (pwm_auto_temp[1])
+ * 1  2  : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 1  3  : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ */
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int ap = sensor_attr_2->nr;
+
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
+		       data->pwm_auto_temp[ap]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int ap = sensor_attr_2->nr;
+	int reg;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+
+	mutex_lock(&data->update_lock);
+
+	/* sync the data cache */
+	reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+	data->pwm_ctl[0] = reg & 0xf;
+	data->pwm_ctl[1] = (reg >> 4) & 0xf;
+
+	data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val);
+	vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap),
+		      data->pwm_auto_temp[ap]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_pwm mapping table:
+ * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't
+ * be changed.
+ *
+ * ix ap : description
+ * -------------------
+ * 0  0  : pwm1 off                   (pwm_auto_pwm[0][0], hard-wired to 0)
+ * 0  1  : pwm1 low speed duty cycle  (pwm_auto_pwm[0][1])
+ * 0  2  : pwm1 high speed duty cycle (pwm_auto_pwm[0][2])
+ * 0  3  : pwm1 full speed            (pwm_auto_pwm[0][3], hard-wired to 255)
+ * 1  0  : pwm2 off                   (pwm_auto_pwm[1][0], hard-wired to 0)
+ * 1  1  : pwm2 low speed duty cycle  (pwm_auto_pwm[1][1])
+ * 1  2  : pwm2 high speed duty cycle (pwm_auto_pwm[1][2])
+ * 1  3  : pwm2 full speed            (pwm_auto_pwm[1][3], hard-wired to 255)
+ */
+
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int ap = sensor_attr_2->nr;
+
+	return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]);
+}
+
+static ssize_t set_pwm_auto_point_pwm(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr_2 =
+						to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int ap = sensor_attr_2->nr;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_auto_pwm[ix][ap] = clamp_val(val, 0, 255);
+	vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
+		      data->pwm_auto_pwm[ix][ap]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms)
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+
+	return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct vt1211_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t show_alarms(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct vt1211_data *data = vt1211_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+/* ---------------------------------------------------------------------
+ * Device attribute structs
+ * --------------------------------------------------------------------- */
+
+#define SENSOR_ATTR_IN(ix) \
+{	SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \
+		show_in, NULL, SHOW_IN_INPUT, ix), \
+	SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+		show_in, set_in, SHOW_SET_IN_MIN, ix), \
+	SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+		show_in, set_in, SHOW_SET_IN_MAX, ix), \
+	SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \
+		show_in, NULL, SHOW_IN_ALARM, ix) \
+}
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in[][4] = {
+	SENSOR_ATTR_IN(0),
+	SENSOR_ATTR_IN(1),
+	SENSOR_ATTR_IN(2),
+	SENSOR_ATTR_IN(3),
+	SENSOR_ATTR_IN(4),
+	SENSOR_ATTR_IN(5)
+};
+
+#define IN_UNIT_ATTRS(X)			\
+{	&vt1211_sysfs_in[X][0].dev_attr.attr,	\
+	&vt1211_sysfs_in[X][1].dev_attr.attr,	\
+	&vt1211_sysfs_in[X][2].dev_attr.attr,	\
+	&vt1211_sysfs_in[X][3].dev_attr.attr,	\
+	NULL					\
+}
+
+static struct attribute *vt1211_in_attr[][5] = {
+	IN_UNIT_ATTRS(0),
+	IN_UNIT_ATTRS(1),
+	IN_UNIT_ATTRS(2),
+	IN_UNIT_ATTRS(3),
+	IN_UNIT_ATTRS(4),
+	IN_UNIT_ATTRS(5)
+};
+
+static const struct attribute_group vt1211_in_attr_group[] = {
+	{ .attrs = vt1211_in_attr[0] },
+	{ .attrs = vt1211_in_attr[1] },
+	{ .attrs = vt1211_in_attr[2] },
+	{ .attrs = vt1211_in_attr[3] },
+	{ .attrs = vt1211_in_attr[4] },
+	{ .attrs = vt1211_in_attr[5] }
+};
+
+#define SENSOR_ATTR_TEMP(ix) \
+{	SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \
+		show_temp, NULL, SHOW_TEMP_INPUT, ix-1), \
+	SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+		show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1), \
+	SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \
+		show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1), \
+	SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+		show_temp, NULL, SHOW_TEMP_ALARM, ix-1) \
+}
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp[][4] = {
+	SENSOR_ATTR_TEMP(1),
+	SENSOR_ATTR_TEMP(2),
+	SENSOR_ATTR_TEMP(3),
+	SENSOR_ATTR_TEMP(4),
+	SENSOR_ATTR_TEMP(5),
+	SENSOR_ATTR_TEMP(6),
+	SENSOR_ATTR_TEMP(7),
+};
+
+#define TEMP_UNIT_ATTRS(X)			\
+{	&vt1211_sysfs_temp[X][0].dev_attr.attr,	\
+	&vt1211_sysfs_temp[X][1].dev_attr.attr,	\
+	&vt1211_sysfs_temp[X][2].dev_attr.attr,	\
+	&vt1211_sysfs_temp[X][3].dev_attr.attr,	\
+	NULL					\
+}
+
+static struct attribute *vt1211_temp_attr[][5] = {
+	TEMP_UNIT_ATTRS(0),
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2),
+	TEMP_UNIT_ATTRS(3),
+	TEMP_UNIT_ATTRS(4),
+	TEMP_UNIT_ATTRS(5),
+	TEMP_UNIT_ATTRS(6)
+};
+
+static const struct attribute_group vt1211_temp_attr_group[] = {
+	{ .attrs = vt1211_temp_attr[0] },
+	{ .attrs = vt1211_temp_attr[1] },
+	{ .attrs = vt1211_temp_attr[2] },
+	{ .attrs = vt1211_temp_attr[3] },
+	{ .attrs = vt1211_temp_attr[4] },
+	{ .attrs = vt1211_temp_attr[5] },
+	{ .attrs = vt1211_temp_attr[6] }
+};
+
+#define SENSOR_ATTR_FAN(ix) \
+	SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \
+		show_fan, NULL, SHOW_FAN_INPUT, ix-1), \
+	SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+		show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \
+	SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \
+		show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \
+	SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+		show_fan, NULL, SHOW_FAN_ALARM, ix-1)
+
+#define SENSOR_ATTR_PWM(ix) \
+	SENSOR_ATTR_2(pwm##ix, S_IRUGO, \
+		show_pwm, NULL, SHOW_PWM, ix-1), \
+	SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \
+		show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \
+	SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \
+		show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ(ix) \
+	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+		show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ_RO(ix) \
+	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+		show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \
+	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \
+		show_pwm_auto_point_temp, set_pwm_auto_point_temp, \
+		ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \
+	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \
+		show_pwm_auto_point_temp, NULL, \
+		ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \
+	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \
+		show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \
+		ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \
+	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \
+		show_pwm_auto_point_pwm, NULL, \
+		ap-1, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {
+	SENSOR_ATTR_FAN(1),
+	SENSOR_ATTR_FAN(2),
+	SENSOR_ATTR_PWM(1),
+	SENSOR_ATTR_PWM(2),
+	SENSOR_ATTR_PWM_FREQ(1),
+	SENSOR_ATTR_PWM_FREQ_RO(2),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),
+	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),
+	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),
+};
+
+static struct device_attribute vt1211_sysfs_misc[] = {
+	__ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),
+	__ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),
+	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(alarms, S_IRUGO, show_alarms, NULL),
+};
+
+/* ---------------------------------------------------------------------
+ * Device registration and initialization
+ * --------------------------------------------------------------------- */
+
+static void vt1211_init_device(struct vt1211_data *data)
+{
+	/* set VRM */
+	data->vrm = vid_which_vrm();
+
+	/* Read (and initialize) UCH config */
+	data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);
+	if (uch_config > -1) {
+		data->uch_config = (data->uch_config & 0x83) |
+				   (uch_config << 2);
+		vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);
+	}
+
+	/*
+	 * Initialize the interrupt mode (if request at module load time).
+	 * The VT1211 implements 3 different modes for clearing interrupts:
+	 * 0: Clear INT when status register is read. Regenerate INT as long
+	 *    as temp stays above hysteresis limit.
+	 * 1: Clear INT when status register is read. DON'T regenerate INT
+	 *    until temp falls below hysteresis limit and exceeds hot limit
+	 *    again.
+	 * 2: Clear INT when temp falls below max limit.
+	 *
+	 * The driver only allows to force mode 0 since that's the only one
+	 * that makes sense for 'sensors'
+	 */
+	if (int_mode == 0) {
+		vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);
+		vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);
+	}
+
+	/* Fill in some hard wired values into our data struct */
+	data->pwm_auto_pwm[0][3] = 255;
+	data->pwm_auto_pwm[1][3] = 255;
+}
+
+static void vt1211_remove_sysfs(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++)
+		sysfs_remove_group(&dev->kobj, &vt1211_in_attr_group[i]);
+
+	for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++)
+		sysfs_remove_group(&dev->kobj, &vt1211_temp_attr_group[i]);
+
+	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+		device_remove_file(dev,
+			&vt1211_sysfs_fan_pwm[i].dev_attr);
+	}
+	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++)
+		device_remove_file(dev, &vt1211_sysfs_misc[i]);
+}
+
+static int vt1211_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vt1211_data *data;
+	struct resource *res;
+	int i, err;
+
+	data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start, resource_size(res),
+				 DRVNAME)) {
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start, (unsigned long)res->end);
+		return -EBUSY;
+	}
+	data->addr = res->start;
+	data->name = DRVNAME;
+	mutex_init(&data->update_lock);
+
+	platform_set_drvdata(pdev, data);
+
+	/* Initialize the VT1211 chip */
+	vt1211_init_device(data);
+
+	/* Create sysfs interface files */
+	for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++) {
+		if (ISVOLT(i, data->uch_config)) {
+			err = sysfs_create_group(&dev->kobj,
+						 &vt1211_in_attr_group[i]);
+			if (err)
+				goto EXIT_DEV_REMOVE;
+		}
+	}
+	for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++) {
+		if (ISTEMP(i, data->uch_config)) {
+			err = sysfs_create_group(&dev->kobj,
+						 &vt1211_temp_attr_group[i]);
+			if (err)
+				goto EXIT_DEV_REMOVE;
+		}
+	}
+	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+		err = device_create_file(dev,
+			&vt1211_sysfs_fan_pwm[i].dev_attr);
+		if (err)
+			goto EXIT_DEV_REMOVE;
+	}
+	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
+		err = device_create_file(dev,
+		       &vt1211_sysfs_misc[i]);
+		if (err)
+			goto EXIT_DEV_REMOVE;
+	}
+
+	/* Register device */
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		dev_err(dev, "Class registration failed (%d)\n", err);
+		goto EXIT_DEV_REMOVE_SILENT;
+	}
+
+	return 0;
+
+EXIT_DEV_REMOVE:
+	dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
+EXIT_DEV_REMOVE_SILENT:
+	vt1211_remove_sysfs(pdev);
+	return err;
+}
+
+static int vt1211_remove(struct platform_device *pdev)
+{
+	struct vt1211_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	vt1211_remove_sysfs(pdev);
+
+	return 0;
+}
+
+static struct platform_driver vt1211_driver = {
+	.driver = {
+		.name  = DRVNAME,
+	},
+	.probe  = vt1211_probe,
+	.remove = vt1211_remove,
+};
+
+static int __init vt1211_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + 0x7f,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed (%d)\n", err);
+		goto EXIT;
+	}
+
+	res.name = pdev->name;
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto EXIT_DEV_PUT;
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto EXIT_DEV_PUT;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto EXIT_DEV_PUT;
+	}
+
+	return 0;
+
+EXIT_DEV_PUT:
+	platform_device_put(pdev);
+EXIT:
+	return err;
+}
+
+static int __init vt1211_find(int sio_cip, unsigned short *address)
+{
+	int err = -ENODEV;
+	int devid;
+
+	superio_enter(sio_cip);
+
+	devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
+	if (devid != SIO_VT1211_ID)
+		goto EXIT;
+
+	superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
+
+	if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
+		pr_warn("HW monitor is disabled, skipping\n");
+		goto EXIT;
+	}
+
+	*address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
+		    (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
+	if (*address == 0) {
+		pr_warn("Base address is not set, skipping\n");
+		goto EXIT;
+	}
+
+	err = 0;
+	pr_info("Found VT1211 chip at 0x%04x, revision %u\n",
+		*address, superio_inb(sio_cip, SIO_VT1211_DEVREV));
+
+EXIT:
+	superio_exit(sio_cip);
+	return err;
+}
+
+static int __init vt1211_init(void)
+{
+	int err;
+	unsigned short address = 0;
+
+	err = vt1211_find(SIO_REG_CIP1, &address);
+	if (err) {
+		err = vt1211_find(SIO_REG_CIP2, &address);
+		if (err)
+			goto EXIT;
+	}
+
+	if ((uch_config < -1) || (uch_config > 31)) {
+		err = -EINVAL;
+		pr_warn("Invalid UCH configuration %d. Choose a value between 0 and 31.\n",
+			uch_config);
+		goto EXIT;
+	}
+
+	if ((int_mode < -1) || (int_mode > 0)) {
+		err = -EINVAL;
+		pr_warn("Invalid interrupt mode %d. Only mode 0 is supported.\n",
+			int_mode);
+		goto EXIT;
+	}
+
+	err = platform_driver_register(&vt1211_driver);
+	if (err)
+		goto EXIT;
+
+	/* Sets global pdev as a side effect */
+	err = vt1211_device_add(address);
+	if (err)
+		goto EXIT_DRV_UNREGISTER;
+
+	return 0;
+
+EXIT_DRV_UNREGISTER:
+	platform_driver_unregister(&vt1211_driver);
+EXIT:
+	return err;
+}
+
+static void __exit vt1211_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&vt1211_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("VT1211 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(vt1211_init);
+module_exit(vt1211_exit);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
new file mode 100644
index 0000000..cb69a8c
--- /dev/null
+++ b/drivers/hwmon/vt8231.c
@@ -0,0 +1,1070 @@
+/*
+ * vt8231.c - Part of lm_sensors, Linux kernel modules
+ *	      for hardware monitoring
+ *
+ * Copyright (c) 2005 Roger Lucas <vt8231@hiddenengine.co.uk>
+ * Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ *		      Aaron M. Marsh <amarsh@sdf.lonestar.org>
+ *
+ * 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.
+ */
+
+/*
+ * Supports VIA VT8231 South Bridge embedded sensors
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static int force_addr;
+module_param(force_addr, int, 0);
+MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
+
+static struct platform_device *pdev;
+
+#define VT8231_EXTENT 0x80
+#define VT8231_BASE_REG 0x70
+#define VT8231_ENABLE_REG 0x74
+
+/*
+ * The VT8231 registers
+ *
+ * The reset value for the input channel configuration is used (Reg 0x4A=0x07)
+ * which sets the selected inputs marked with '*' below if multiple options are
+ * possible:
+ *
+ *		    Voltage Mode	  Temperature Mode
+ *	Sensor	      Linux Id	      Linux Id	      VIA Id
+ *	--------      --------	      --------	      ------
+ *	CPU Diode	N/A		temp1		0
+ *	UIC1		in0		temp2 *		1
+ *	UIC2		in1 *		temp3		2
+ *	UIC3		in2 *		temp4		3
+ *	UIC4		in3 *		temp5		4
+ *	UIC5		in4 *		temp6		5
+ *	3.3V		in5		N/A
+ *
+ * Note that the BIOS may set the configuration register to a different value
+ * to match the motherboard configuration.
+ */
+
+/* fans numbered 0-1 */
+#define VT8231_REG_FAN_MIN(nr)	(0x3b + (nr))
+#define VT8231_REG_FAN(nr)	(0x29 + (nr))
+
+/* Voltage inputs numbered 0-5 */
+
+static const u8 regvolt[]    = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26 };
+static const u8 regvoltmax[] = { 0x3d, 0x2b, 0x2d, 0x2f, 0x31, 0x33 };
+static const u8 regvoltmin[] = { 0x3e, 0x2c, 0x2e, 0x30, 0x32, 0x34 };
+
+/*
+ * Temperatures are numbered 1-6 according to the Linux kernel specification.
+ *
+ * In the VIA datasheet, however, the temperatures are numbered from zero.
+ * Since it is important that this driver can easily be compared to the VIA
+ * datasheet, we will use the VIA numbering within this driver and map the
+ * kernel sysfs device name to the VIA number in the sysfs callback.
+ */
+
+#define VT8231_REG_TEMP_LOW01	0x49
+#define VT8231_REG_TEMP_LOW25	0x4d
+
+static const u8 regtemp[]    = { 0x1f, 0x21, 0x22, 0x23, 0x24, 0x25 };
+static const u8 regtempmax[] = { 0x39, 0x3d, 0x2b, 0x2d, 0x2f, 0x31 };
+static const u8 regtempmin[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 };
+
+#define TEMP_FROM_REG(reg)		(((253 * 4 - (reg)) * 550 + 105) / 210)
+#define TEMP_MAXMIN_FROM_REG(reg)	(((253 - (reg)) * 2200 + 105) / 210)
+#define TEMP_MAXMIN_TO_REG(val)		(253 - ((val) * 210 + 1100) / 2200)
+
+#define VT8231_REG_CONFIG 0x40
+#define VT8231_REG_ALARM1 0x41
+#define VT8231_REG_ALARM2 0x42
+#define VT8231_REG_FANDIV 0x47
+#define VT8231_REG_UCH_CONFIG 0x4a
+#define VT8231_REG_TEMP1_CONFIG 0x4b
+#define VT8231_REG_TEMP2_CONFIG 0x4c
+
+/*
+ * temps 0-5 as numbered in VIA datasheet - see later for mapping to Linux
+ * numbering
+ */
+#define ISTEMP(i, ch_config) ((i) == 0 ? 1 : \
+			      ((ch_config) >> ((i)+1)) & 0x01)
+/* voltages 0-5 */
+#define ISVOLT(i, ch_config) ((i) == 5 ? 1 : \
+			      !(((ch_config) >> ((i)+2)) & 0x01))
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+/*
+ * NB  The values returned here are NOT temperatures.  The calibration curves
+ *     for the thermistor curves are board-specific and must go in the
+ *     sensors.conf file.  Temperature sensors are actually ten bits, but the
+ *     VIA datasheet only considers the 8 MSBs obtained from the regtemp[]
+ *     register.  The temperature value returned should have a magnitude of 3,
+ *     so we use the VIA scaling as the "true" scaling and use the remaining 2
+ *     LSBs as fractional precision.
+ *
+ *     All the on-chip hardware temperature comparisons for the alarms are only
+ *     8-bits wide, and compare against the 8 MSBs of the temperature.  The bits
+ *     in the registers VT8231_REG_TEMP_LOW01 and VT8231_REG_TEMP_LOW25 are
+ *     ignored.
+ */
+
+/*
+ ****** FAN RPM CONVERSIONS ********
+ * This chip saturates back at 0, not at 255 like many the other chips.
+ * So, 0 means 0 RPM
+ */
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm <= 0 || rpm > 1310720)
+		return 0;
+	return clamp_val(1310720 / (rpm * div), 1, 255);
+}
+
+#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
+
+struct vt8231_data {
+	unsigned short addr;
+	const char *name;
+
+	struct mutex update_lock;
+	struct device *hwmon_dev;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[6];		/* Register value */
+	u8 in_max[6];		/* Register value */
+	u8 in_min[6];		/* Register value */
+	u16 temp[6];		/* Register value 10 bit, right aligned */
+	u8 temp_max[6];		/* Register value */
+	u8 temp_min[6];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 alarms;		/* Register encoding */
+	u8 uch_config;
+};
+
+static struct pci_dev *s_bridge;
+static int vt8231_probe(struct platform_device *pdev);
+static int vt8231_remove(struct platform_device *pdev);
+static struct vt8231_data *vt8231_update_device(struct device *dev);
+static void vt8231_init_device(struct vt8231_data *data);
+
+static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
+{
+	return inb_p(data->addr + reg);
+}
+
+static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
+					u8 value)
+{
+	outb_p(value, data->addr + reg);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n", ((data->in[nr] - 3) * 10000) / 958);
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n", ((data->in_min[nr] - 3) * 10000) / 958);
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n", (((data->in_max[nr] - 3) * 10000) / 958));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
+	vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
+	vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* Special case for input 5 as this has 3.3V scaling built into the chip */
+static ssize_t show_in5(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		(((data->in[5] - 3) * 10000 * 54) / (958 * 34)));
+}
+
+static ssize_t show_in5_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		(((data->in_min[5] - 3) * 10000 * 54) / (958 * 34)));
+}
+
+static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		(((data->in_max[5] - 3) * 10000 * 54) / (958 * 34)));
+}
+
+static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+				    0, 255);
+	vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+				    0, 255);
+	vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define define_voltage_sysfs(offset)				\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset)
+
+define_voltage_sysfs(0);
+define_voltage_sysfs(1);
+define_voltage_sysfs(2);
+define_voltage_sysfs(3);
+define_voltage_sysfs(4);
+
+static DEVICE_ATTR(in5_input, S_IRUGO, show_in5, NULL);
+static DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR, show_in5_min, set_in5_min);
+static DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR, show_in5_max, set_in5_max);
+
+/* Temperatures */
+static ssize_t show_temp0(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp[0] * 250);
+}
+
+static ssize_t show_temp0_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_max[0] * 1000);
+}
+
+static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_min[0] * 1000);
+}
+
+static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[0] = clamp_val((val + 500) / 1000, 0, 255);
+	vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[0] = clamp_val((val + 500) / 1000, 0, 255);
+	vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_MAXMIN_FROM_REG(data->temp_max[nr]));
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_MAXMIN_FROM_REG(data->temp_min[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
+	vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
+	vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Note that these map the Linux temperature sensor numbering (1-6) to the VIA
+ * temperature sensor numbering (0-5)
+ */
+#define define_temperature_sysfs(offset)				\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+		show_temp, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_max, set_temp_max, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp_min, set_temp_min, offset - 1)
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp0, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp0_max, set_temp0_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp0_min,
+		   set_temp0_min);
+
+define_temperature_sysfs(2);
+define_temperature_sysfs(3);
+define_temperature_sysfs(4);
+define_temperature_sysfs(5);
+define_temperature_sysfs(6);
+
+/* Fans */
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+				DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+			DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	unsigned long val;
+	int nr = sensor_attr->index;
+	int old = vt8231_read_value(data, VT8231_REG_FANDIV);
+	long min = FAN_FROM_REG(data->fan_min[nr],
+				 DIV_FROM_REG(data->fan_div[nr]));
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 1:
+		data->fan_div[nr] = 0;
+		break;
+	case 2:
+		data->fan_div[nr] = 1;
+		break;
+	case 4:
+		data->fan_div[nr] = 2;
+		break;
+	case 8:
+		data->fan_div[nr] = 3;
+		break;
+	default:
+		dev_err(dev,
+			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+			val);
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	/* Correct the fan minimum speed */
+	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+
+	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
+	vt8231_write_value(data, VT8231_REG_FANDIV, old);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+#define define_fan_sysfs(offset)					\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1)
+
+define_fan_sysfs(1);
+define_fan_sysfs(2);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	struct vt8231_data *data = vt8231_update_device(dev);
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *vt8231_attributes_temps[6][5] = {
+	{
+		&dev_attr_temp1_input.attr,
+		&dev_attr_temp1_max_hyst.attr,
+		&dev_attr_temp1_max.attr,
+		&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp2_input.dev_attr.attr,
+		&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+		&sensor_dev_attr_temp2_max.dev_attr.attr,
+		&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp3_input.dev_attr.attr,
+		&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+		&sensor_dev_attr_temp3_max.dev_attr.attr,
+		&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp4_input.dev_attr.attr,
+		&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+		&sensor_dev_attr_temp4_max.dev_attr.attr,
+		&sensor_dev_attr_temp4_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp5_input.dev_attr.attr,
+		&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+		&sensor_dev_attr_temp5_max.dev_attr.attr,
+		&sensor_dev_attr_temp5_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp6_input.dev_attr.attr,
+		&sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
+		&sensor_dev_attr_temp6_max.dev_attr.attr,
+		&sensor_dev_attr_temp6_alarm.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group vt8231_group_temps[6] = {
+	{ .attrs = vt8231_attributes_temps[0] },
+	{ .attrs = vt8231_attributes_temps[1] },
+	{ .attrs = vt8231_attributes_temps[2] },
+	{ .attrs = vt8231_attributes_temps[3] },
+	{ .attrs = vt8231_attributes_temps[4] },
+	{ .attrs = vt8231_attributes_temps[5] },
+};
+
+static struct attribute *vt8231_attributes_volts[6][5] = {
+	{
+		&sensor_dev_attr_in0_input.dev_attr.attr,
+		&sensor_dev_attr_in0_min.dev_attr.attr,
+		&sensor_dev_attr_in0_max.dev_attr.attr,
+		&sensor_dev_attr_in0_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in1_input.dev_attr.attr,
+		&sensor_dev_attr_in1_min.dev_attr.attr,
+		&sensor_dev_attr_in1_max.dev_attr.attr,
+		&sensor_dev_attr_in1_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in2_input.dev_attr.attr,
+		&sensor_dev_attr_in2_min.dev_attr.attr,
+		&sensor_dev_attr_in2_max.dev_attr.attr,
+		&sensor_dev_attr_in2_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in3_input.dev_attr.attr,
+		&sensor_dev_attr_in3_min.dev_attr.attr,
+		&sensor_dev_attr_in3_max.dev_attr.attr,
+		&sensor_dev_attr_in3_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_in4_input.dev_attr.attr,
+		&sensor_dev_attr_in4_min.dev_attr.attr,
+		&sensor_dev_attr_in4_max.dev_attr.attr,
+		&sensor_dev_attr_in4_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&dev_attr_in5_input.attr,
+		&dev_attr_in5_min.attr,
+		&dev_attr_in5_max.attr,
+		&sensor_dev_attr_in5_alarm.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group vt8231_group_volts[6] = {
+	{ .attrs = vt8231_attributes_volts[0] },
+	{ .attrs = vt8231_attributes_volts[1] },
+	{ .attrs = vt8231_attributes_volts[2] },
+	{ .attrs = vt8231_attributes_volts[3] },
+	{ .attrs = vt8231_attributes_volts[4] },
+	{ .attrs = vt8231_attributes_volts[5] },
+};
+
+static struct attribute *vt8231_attributes[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group vt8231_group = {
+	.attrs = vt8231_attributes,
+};
+
+static struct platform_driver vt8231_driver = {
+	.driver = {
+		.name	= "vt8231",
+	},
+	.probe	= vt8231_probe,
+	.remove	= vt8231_remove,
+};
+
+static const struct pci_device_id vt8231_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, vt8231_pci_ids);
+
+static int vt8231_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *id);
+
+static struct pci_driver vt8231_pci_driver = {
+	.name		= "vt8231",
+	.id_table	= vt8231_pci_ids,
+	.probe		= vt8231_pci_probe,
+};
+
+static int vt8231_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct vt8231_data *data;
+	int err = 0, i;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT,
+				 vt8231_driver.driver.name)) {
+		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start, (unsigned long)res->end);
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct vt8231_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, data);
+	data->addr = res->start;
+	data->name = "vt8231";
+
+	mutex_init(&data->update_lock);
+	vt8231_init_device(data);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group);
+	if (err)
+		return err;
+
+	/* Must update device information to find out the config field */
+	data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
+
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
+		if (ISTEMP(i, data->uch_config)) {
+			err = sysfs_create_group(&pdev->dev.kobj,
+						 &vt8231_group_temps[i]);
+			if (err)
+				goto exit_remove_files;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
+		if (ISVOLT(i, data->uch_config)) {
+			err = sysfs_create_group(&pdev->dev.kobj,
+						 &vt8231_group_volts[i]);
+			if (err)
+				goto exit_remove_files;
+		}
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+	return 0;
+
+exit_remove_files:
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
+
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
+
+	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
+	return err;
+}
+
+static int vt8231_remove(struct platform_device *pdev)
+{
+	struct vt8231_data *data = platform_get_drvdata(pdev);
+	int i;
+
+	hwmon_device_unregister(data->hwmon_dev);
+
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
+
+	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
+
+	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
+
+	return 0;
+}
+
+static void vt8231_init_device(struct vt8231_data *data)
+{
+	vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
+	vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
+}
+
+static struct vt8231_data *vt8231_update_device(struct device *dev)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	int i;
+	u16 low;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		for (i = 0; i < 6; i++) {
+			if (ISVOLT(i, data->uch_config)) {
+				data->in[i] = vt8231_read_value(data,
+						regvolt[i]);
+				data->in_min[i] = vt8231_read_value(data,
+						regvoltmin[i]);
+				data->in_max[i] = vt8231_read_value(data,
+						regvoltmax[i]);
+			}
+		}
+		for (i = 0; i < 2; i++) {
+			data->fan[i] = vt8231_read_value(data,
+						VT8231_REG_FAN(i));
+			data->fan_min[i] = vt8231_read_value(data,
+						VT8231_REG_FAN_MIN(i));
+		}
+
+		low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
+		low = (low >> 6) | ((low & 0x30) >> 2)
+		    | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
+		for (i = 0; i < 6; i++) {
+			if (ISTEMP(i, data->uch_config)) {
+				data->temp[i] = (vt8231_read_value(data,
+						       regtemp[i]) << 2)
+						| ((low >> (2 * i)) & 0x03);
+				data->temp_max[i] = vt8231_read_value(data,
+						      regtempmax[i]);
+				data->temp_min[i] = vt8231_read_value(data,
+						      regtempmin[i]);
+			}
+		}
+
+		i = vt8231_read_value(data, VT8231_REG_FANDIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = i >> 6;
+		data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
+			(vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
+
+		/* Set alarm flags correctly */
+		if (!data->fan[0] && data->fan_min[0])
+			data->alarms |= 0x40;
+		else if (data->fan[0] && !data->fan_min[0])
+			data->alarms &= ~0x40;
+
+		if (!data->fan[1] && data->fan_min[1])
+			data->alarms |= 0x80;
+		else if (data->fan[1] && !data->fan_min[1])
+			data->alarms &= ~0x80;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int vt8231_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + VT8231_EXTENT - 1,
+		.name	= "vt8231",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc("vt8231", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int vt8231_pci_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	u16 address, val;
+	if (force_addr) {
+		address = force_addr & 0xff00;
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
+			 address);
+
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+			return -ENODEV;
+	}
+
+	if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
+							&val))
+		return -ENODEV;
+
+	address = val & ~(VT8231_EXTENT - 1);
+	if (address == 0) {
+		dev_err(&dev->dev, "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+	if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
+							&val))
+		return -ENODEV;
+
+	if (!(val & 0x0001)) {
+		dev_warn(&dev->dev, "enabling sensors\n");
+		if (PCIBIOS_SUCCESSFUL !=
+			pci_write_config_word(dev, VT8231_ENABLE_REG,
+							val | 0x0001))
+			return -ENODEV;
+	}
+
+	if (platform_driver_register(&vt8231_driver))
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	if (vt8231_device_add(address))
+		goto exit_unregister;
+
+	/*
+	 * Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+
+	/*
+	 * We do, however, mark ourselves as using the PCI device to stop it
+	 * getting unloaded.
+	 */
+	s_bridge = pci_dev_get(dev);
+	return -ENODEV;
+
+exit_unregister:
+	platform_driver_unregister(&vt8231_driver);
+exit:
+	return -ENODEV;
+}
+
+static int __init sm_vt8231_init(void)
+{
+	return pci_register_driver(&vt8231_pci_driver);
+}
+
+static void __exit sm_vt8231_exit(void)
+{
+	pci_unregister_driver(&vt8231_pci_driver);
+	if (s_bridge != NULL) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&vt8231_driver);
+		pci_dev_put(s_bridge);
+		s_bridge = NULL;
+	}
+}
+
+MODULE_AUTHOR("Roger Lucas <vt8231@hiddenengine.co.uk>");
+MODULE_DESCRIPTION("VT8231 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(sm_vt8231_init);
+module_exit(sm_vt8231_exit);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
new file mode 100644
index 0000000..697007a
--- /dev/null
+++ b/drivers/hwmon/w83627ehf.c
@@ -0,0 +1,2880 @@
+/*
+ *  w83627ehf - Driver for the hardware monitoring functionality of
+ *		the Winbond W83627EHF Super-I/O chip
+ *  Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
+ *  Copyright (C) 2006  Yuan Mu (Winbond),
+ *			Rudolf Marek <r.marek@assembler.cz>
+ *			David Hubbard <david.c.hubbard@gmail.com>
+ *			Daniel J Blueman <daniel.blueman@gmail.com>
+ *  Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
+ *
+ *  Shamelessly ripped from the w83627hf driver
+ *  Copyright (C) 2003  Mark Studebaker
+ *
+ *  Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
+ *  in testing and debugging this driver.
+ *
+ *  This driver also supports the W83627EHG, which is the lead-free
+ *  version of the W83627EHF.
+ *
+ *  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.
+ *
+ *  Supports the following chips:
+ *
+ *  Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+ *  w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
+ *					       0x8860 0xa1
+ *  w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
+ *  w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
+ *  w83627uhg    8      2       2       3      0xa230 0xc1    0x5ca3
+ *  w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
+ *  w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
+ *  nct6775f     9      4       3       9      0xb470 0xc1    0x5ca3
+ *  nct6776f     9      5       3       9      0xC330 0xc1    0x5ca3
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include "lm75.h"
+
+enum kinds {
+	w83627ehf, w83627dhg, w83627dhg_p, w83627uhg,
+	w83667hg, w83667hg_b, nct6775, nct6776,
+};
+
+/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
+static const char * const w83627ehf_device_names[] = {
+	"w83627ehf",
+	"w83627dhg",
+	"w83627dhg",
+	"w83627uhg",
+	"w83667hg",
+	"w83667hg",
+	"nct6775",
+	"nct6776",
+};
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static unsigned short fan_debounce;
+module_param(fan_debounce, ushort, 0);
+MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
+
+#define DRVNAME "w83627ehf"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define W83627EHF_LD_HWM	0x0b
+#define W83667HG_LD_VID		0x0d
+
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM10	0x2C	/* GPIO3, GPIO4 selection */
+#define SIO_REG_ENABLE		0x30	/* Logical device enable */
+#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL	0xF0	/* VID control */
+#define SIO_REG_VID_DATA	0xF1	/* VID data */
+
+#define SIO_W83627EHF_ID	0x8850
+#define SIO_W83627EHG_ID	0x8860
+#define SIO_W83627DHG_ID	0xa020
+#define SIO_W83627DHG_P_ID	0xb070
+#define SIO_W83627UHG_ID	0xa230
+#define SIO_W83667HG_ID		0xa510
+#define SIO_W83667HG_B_ID	0xb350
+#define SIO_NCT6775_ID		0xb470
+#define SIO_NCT6776_ID		0xc330
+#define SIO_ID_MASK		0xFFF0
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+	outb(reg, ioreg);
+	outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+	outb(reg, ioreg);
+	return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+	outb(SIO_REG_LDSEL, ioreg);
+	outb(ld, ioreg + 1);
+}
+
+static inline void
+superio_enter(int ioreg)
+{
+	outb(0x87, ioreg);
+	outb(0x87, ioreg);
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+	outb(0xaa, ioreg);
+	outb(0x02, ioreg);
+	outb(0x02, ioreg + 1);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT	(~7)
+#define IOREGION_OFFSET		5
+#define IOREGION_LENGTH		2
+#define ADDR_REG_OFFSET		0
+#define DATA_REG_OFFSET		1
+
+#define W83627EHF_REG_BANK		0x4E
+#define W83627EHF_REG_CONFIG		0x40
+
+/*
+ * Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58
+ */
+
+static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
+static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
+
+/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
+#define W83627EHF_REG_IN_MAX(nr)	((nr < 7) ? (0x2b + (nr) * 2) : \
+					 (0x554 + (((nr) - 7) * 2)))
+#define W83627EHF_REG_IN_MIN(nr)	((nr < 7) ? (0x2c + (nr) * 2) : \
+					 (0x555 + (((nr) - 7) * 2)))
+#define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
+					 (0x550 + (nr) - 7))
+
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
+
+/* Fan clock dividers are spread over the following five registers */
+#define W83627EHF_REG_FANDIV1		0x47
+#define W83627EHF_REG_FANDIV2		0x4B
+#define W83627EHF_REG_VBAT		0x5D
+#define W83627EHF_REG_DIODE		0x59
+#define W83627EHF_REG_SMI_OVT		0x4C
+
+/* NCT6775F has its own fan divider registers */
+#define NCT6775_REG_FANDIV1		0x506
+#define NCT6775_REG_FANDIV2		0x507
+#define NCT6775_REG_FAN_DEBOUNCE	0xf0
+
+#define W83627EHF_REG_ALARM1		0x459
+#define W83627EHF_REG_ALARM2		0x45A
+#define W83627EHF_REG_ALARM3		0x45B
+
+#define W83627EHF_REG_CASEOPEN_DET	0x42 /* SMI STATUS #2 */
+#define W83627EHF_REG_CASEOPEN_CLR	0x46 /* SMI MASK #3 */
+
+/* SmartFan registers */
+#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
+#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
+
+/* DC or PWM output fan configuration */
+static const u8 W83627EHF_REG_PWM_ENABLE[] = {
+	0x04,			/* SYS FAN0 output mode and PWM mode */
+	0x04,			/* CPU FAN0 output mode and PWM mode */
+	0x12,			/* AUX FAN mode */
+	0x62,			/* CPU FAN1 mode */
+};
+
+static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
+static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
+
+/* FAN Duty Cycle, be used to control */
+static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
+
+/* Advanced Fan control, some values are common for all fans */
+static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
+static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
+
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
+						= { 0xff, 0x67, 0xff, 0x69 };
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
+						= { 0xff, 0x68, 0xff, 0x6a };
+
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
+						= { 0x68, 0x6a, 0x6c };
+
+static const u16 W83627EHF_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
+
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
+
+static const u16 NCT6775_REG_TEMP[]
+	= { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
+static const u16 NCT6775_REG_TEMP_CONFIG[]
+	= { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[]
+	= { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[]
+	= { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
+static const u16 NCT6775_REG_TEMP_SOURCE[]
+	= { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
+
+static const char *const w83667hg_b_temp_label[] = {
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMDTSI",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4"
+};
+
+static const char *const nct6775_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMD SB-TSI",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4",
+	"PECI Agent 5",
+	"PECI Agent 6",
+	"PECI Agent 7",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP"
+};
+
+static const char *const nct6776_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP"
+};
+
+#define NUM_REG_TEMP	ARRAY_SIZE(NCT6775_REG_TEMP)
+
+static int is_word_sized(u16 reg)
+{
+	return ((((reg & 0xff00) == 0x100
+	      || (reg & 0xff00) == 0x200)
+	     && ((reg & 0x00ff) == 0x50
+	      || (reg & 0x00ff) == 0x53
+	      || (reg & 0x00ff) == 0x55))
+	     || (reg & 0xfff0) == 0x630
+	     || reg == 0x640 || reg == 0x642
+	     || ((reg & 0xfff0) == 0x650
+		 && (reg & 0x000f) >= 0x06)
+	     || reg == 0x73 || reg == 0x75 || reg == 0x77
+		);
+}
+
+/*
+ * Conversions
+ */
+
+/* 1 is PWM mode, output in ms */
+static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+	return mode ? 100 * reg : 400 * reg;
+}
+
+static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+	return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400),
+			 1, 255);
+}
+
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
+{
+	if (reg == 0 || reg == 255)
+		return 0;
+	return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+	if ((reg & 0xff1f) == 0xff1f)
+		return 0;
+
+	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+	if (reg == 0)
+		return 0;
+
+	return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+	if (reg == 0 || reg == 0xffff)
+		return 0;
+
+	/*
+	 * Even though the registers are 16 bit wide, the fan divisor
+	 * still applies.
+	 */
+	return 1350000U / (reg << divreg);
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+	return 1 << reg;
+}
+
+/*
+ * Some of the voltage inputs have internal scaling, the tables below
+ * contain 8 (the ADC LSB in mV) * scaling factor * 100
+ */
+static const u16 scale_in_common[10] = {
+	800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800
+};
+static const u16 scale_in_w83627uhg[9] = {
+	800, 800, 3328, 3424, 800, 800, 0, 3328, 3400
+};
+
+static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in)
+{
+	return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
+}
+
+static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in)
+{
+	return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
+}
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct w83627ehf_data {
+	int addr;	/* IO base of hw monitor block */
+	const char *name;
+
+	struct device *hwmon_dev;
+	struct mutex lock;
+
+	u16 reg_temp[NUM_REG_TEMP];
+	u16 reg_temp_over[NUM_REG_TEMP];
+	u16 reg_temp_hyst[NUM_REG_TEMP];
+	u16 reg_temp_config[NUM_REG_TEMP];
+	u8 temp_src[NUM_REG_TEMP];
+	const char * const *temp_label;
+
+	const u16 *REG_PWM;
+	const u16 *REG_TARGET;
+	const u16 *REG_FAN;
+	const u16 *REG_FAN_MIN;
+	const u16 *REG_FAN_START_OUTPUT;
+	const u16 *REG_FAN_STOP_OUTPUT;
+	const u16 *REG_FAN_STOP_TIME;
+	const u16 *REG_FAN_MAX_OUTPUT;
+	const u16 *REG_FAN_STEP_OUTPUT;
+	const u16 *scale_in;
+
+	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* Register values */
+	u8 bank;		/* current register bank */
+	u8 in_num;		/* number of in inputs we have */
+	u8 in[10];		/* Register value */
+	u8 in_max[10];		/* Register value */
+	u8 in_min[10];		/* Register value */
+	unsigned int rpm[5];
+	u16 fan_min[5];
+	u8 fan_div[5];
+	u8 has_fan;		/* some fan inputs can be disabled */
+	u8 has_fan_min;		/* some fans don't have min register */
+	bool has_fan_div;
+	u8 temp_type[3];
+	s8 temp_offset[3];
+	s16 temp[9];
+	s16 temp_max[9];
+	s16 temp_max_hyst[9];
+	u32 alarms;
+	u8 caseopen;
+
+	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
+	u8 pwm_enable[4]; /* 1->manual
+			   * 2->thermal cruise mode (also called SmartFan I)
+			   * 3->fan speed cruise mode
+			   * 4->variable thermal cruise (also called
+			   * SmartFan III)
+			   * 5->enhanced variable thermal cruise (also called
+			   * SmartFan IV)
+			   */
+	u8 pwm_enable_orig[4];	/* original value of pwm_enable */
+	u8 pwm_num;		/* number of pwm */
+	u8 pwm[4];
+	u8 target_temp[4];
+	u8 tolerance[4];
+
+	u8 fan_start_output[4]; /* minimum fan speed when spinning up */
+	u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
+	u8 fan_stop_time[4]; /* time at minimum before disabling fan */
+	u8 fan_max_output[4]; /* maximum fan speed */
+	u8 fan_step_output[4]; /* rate of change output value */
+
+	u8 vid;
+	u8 vrm;
+
+	u16 have_temp;
+	u16 have_temp_offset;
+	u8 in6_skip:1;
+	u8 temp3_val_only:1;
+
+#ifdef CONFIG_PM
+	/* Remember extra register values over suspend/resume */
+	u8 vbat;
+	u8 fandiv1;
+	u8 fandiv2;
+#endif
+};
+
+struct w83627ehf_sio_data {
+	int sioreg;
+	enum kinds kind;
+};
+
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
+static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
+{
+	u8 bank = reg >> 8;
+	if (data->bank != bank) {
+		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+		outb_p(bank, data->addr + DATA_REG_OFFSET);
+		data->bank = bank;
+	}
+}
+
+static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
+{
+	int res, word_sized = is_word_sized(reg);
+
+	mutex_lock(&data->lock);
+
+	w83627ehf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+	res = inb_p(data->addr + DATA_REG_OFFSET);
+	if (word_sized) {
+		outb_p((reg & 0xff) + 1,
+		       data->addr + ADDR_REG_OFFSET);
+		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
+	}
+
+	mutex_unlock(&data->lock);
+	return res;
+}
+
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
+				 u16 value)
+{
+	int word_sized = is_word_sized(reg);
+
+	mutex_lock(&data->lock);
+
+	w83627ehf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+	if (word_sized) {
+		outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
+		outb_p((reg & 0xff) + 1,
+		       data->addr + ADDR_REG_OFFSET);
+	}
+	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+
+	mutex_unlock(&data->lock);
+	return 0;
+}
+
+/* We left-align 8-bit temperature values to make the code simpler */
+static u16 w83627ehf_read_temp(struct w83627ehf_data *data, u16 reg)
+{
+	u16 res;
+
+	res = w83627ehf_read_value(data, reg);
+	if (!is_word_sized(reg))
+		res <<= 8;
+
+	return res;
+}
+
+static int w83627ehf_write_temp(struct w83627ehf_data *data, u16 reg,
+				       u16 value)
+{
+	if (!is_word_sized(reg))
+		value >>= 8;
+	return w83627ehf_write_value(data, reg, value);
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+		    | (data->fan_div[0] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 1:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+		    | ((data->fan_div[1] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 2:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+		    | (data->fan_div[2] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	case 3:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+		    | ((data->fan_div[3] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	}
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
+		    | ((data->fan_div[0] & 0x03) << 4);
+		/* fan5 input control bit is write only, compute the value */
+		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
+		    | ((data->fan_div[0] & 0x04) << 3);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
+		break;
+	case 1:
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
+		    | ((data->fan_div[1] & 0x03) << 6);
+		/* fan5 input control bit is write only, compute the value */
+		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
+		    | ((data->fan_div[1] & 0x04) << 4);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
+		break;
+	case 2:
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
+		    | ((data->fan_div[2] & 0x03) << 6);
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
+		    | ((data->fan_div[2] & 0x04) << 5);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
+		break;
+	case 3:
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
+		    | (data->fan_div[3] & 0x03);
+		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
+		    | ((data->fan_div[3] & 0x04) << 5);
+		w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
+		break;
+	case 4:
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
+		    | ((data->fan_div[4] & 0x03) << 2)
+		    | ((data->fan_div[4] & 0x04) << 5);
+		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+		break;
+	}
+}
+
+static void w83627ehf_write_fan_div_common(struct device *dev,
+					   struct w83627ehf_data *data, int nr)
+{
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+
+	if (sio_data->kind == nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind == nct6775)
+		nct6775_write_fan_div(data, nr);
+	else
+		w83627ehf_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct w83627ehf_data *data)
+{
+	u8 i;
+
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+	data->fan_div[0] = i & 0x7;
+	data->fan_div[1] = (i & 0x70) >> 4;
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+	data->fan_div[2] = i & 0x7;
+	if (data->has_fan & (1<<3))
+		data->fan_div[3] = (i & 0x70) >> 4;
+}
+
+static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
+{
+	int i;
+
+	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+	data->fan_div[0] = (i >> 4) & 0x03;
+	data->fan_div[1] = (i >> 6) & 0x03;
+	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
+	data->fan_div[2] = (i >> 6) & 0x03;
+	i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+	data->fan_div[0] |= (i >> 3) & 0x04;
+	data->fan_div[1] |= (i >> 4) & 0x04;
+	data->fan_div[2] |= (i >> 5) & 0x04;
+	if (data->has_fan & ((1 << 3) | (1 << 4))) {
+		i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+		data->fan_div[3] = i & 0x03;
+		data->fan_div[4] = ((i >> 2) & 0x03)
+				 | ((i >> 5) & 0x04);
+	}
+	if (data->has_fan & (1 << 3)) {
+		i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
+		data->fan_div[3] |= (i >> 5) & 0x04;
+	}
+}
+
+static void w83627ehf_update_fan_div_common(struct device *dev,
+					    struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+
+	if (sio_data->kind == nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind == nct6775)
+		nct6775_update_fan_div(data);
+	else
+		w83627ehf_update_fan_div(data);
+}
+
+static void nct6775_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg, fanmodecfg;
+
+	for (i = 0; i < data->pwm_num; i++) {
+		pwmcfg = w83627ehf_read_value(data,
+					      W83627EHF_REG_PWM_ENABLE[i]);
+		fanmodecfg = w83627ehf_read_value(data,
+						  NCT6775_REG_FAN_MODE[i]);
+		data->pwm_mode[i] =
+		  ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
+		data->tolerance[i] = fanmodecfg & 0x0f;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+	}
+}
+
+static void w83627ehf_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+
+	for (i = 0; i < data->pwm_num; i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+
+		/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
+		if (i != 1) {
+			pwmcfg = w83627ehf_read_value(data,
+					W83627EHF_REG_PWM_ENABLE[i]);
+			tolerance = w83627ehf_read_value(data,
+					W83627EHF_REG_TOLERANCE[i]);
+		}
+		data->pwm_mode[i] =
+			((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+				       & 3) + 1;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+
+		data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
+	}
+}
+
+static void w83627ehf_update_pwm_common(struct device *dev,
+					struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
+		nct6775_update_pwm(data);
+	else
+		w83627ehf_update_pwm(data);
+}
+
+static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
+	 || !data->valid) {
+		/* Fan clock dividers */
+		w83627ehf_update_fan_div_common(dev, data);
+
+		/* Measured voltages and limits */
+		for (i = 0; i < data->in_num; i++) {
+			if ((i == 6) && data->in6_skip)
+				continue;
+
+			data->in[i] = w83627ehf_read_value(data,
+				      W83627EHF_REG_IN(i));
+			data->in_min[i] = w83627ehf_read_value(data,
+					  W83627EHF_REG_IN_MIN(i));
+			data->in_max[i] = w83627ehf_read_value(data,
+					  W83627EHF_REG_IN_MAX(i));
+		}
+
+		/* Measured fan speeds and limits */
+		for (i = 0; i < 5; i++) {
+			u16 reg;
+
+			if (!(data->has_fan & (1 << i)))
+				continue;
+
+			reg = w83627ehf_read_value(data, data->REG_FAN[i]);
+			data->rpm[i] = data->fan_from_reg(reg,
+							  data->fan_div[i]);
+
+			if (data->has_fan_min & (1 << i))
+				data->fan_min[i] = w83627ehf_read_value(data,
+					   data->REG_FAN_MIN[i]);
+
+			/*
+			 * If we failed to measure the fan speed and clock
+			 * divider can be increased, let's try that for next
+			 * time
+			 */
+			if (data->has_fan_div
+			    && (reg >= 0xff || (sio_data->kind == nct6775
+						&& reg == 0x00))
+			    && data->fan_div[i] < 0x07) {
+				dev_dbg(dev,
+					"Increasing fan%d clock divider from %u to %u\n",
+					i + 1, div_from_reg(data->fan_div[i]),
+					div_from_reg(data->fan_div[i] + 1));
+				data->fan_div[i]++;
+				w83627ehf_write_fan_div_common(dev, data, i);
+				/* Preserve min limit if possible */
+				if ((data->has_fan_min & (1 << i))
+				 && data->fan_min[i] >= 2
+				 && data->fan_min[i] != 255)
+					w83627ehf_write_value(data,
+						data->REG_FAN_MIN[i],
+						(data->fan_min[i] /= 2));
+			}
+		}
+
+		w83627ehf_update_pwm_common(dev, data);
+
+		for (i = 0; i < data->pwm_num; i++) {
+			if (!(data->has_fan & (1 << i)))
+				continue;
+
+			data->fan_start_output[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_START_OUTPUT[i]);
+			data->fan_stop_output[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_OUTPUT[i]);
+			data->fan_stop_time[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_TIME[i]);
+
+			if (data->REG_FAN_MAX_OUTPUT &&
+			    data->REG_FAN_MAX_OUTPUT[i] != 0xff)
+				data->fan_max_output[i] =
+				  w83627ehf_read_value(data,
+						data->REG_FAN_MAX_OUTPUT[i]);
+
+			if (data->REG_FAN_STEP_OUTPUT &&
+			    data->REG_FAN_STEP_OUTPUT[i] != 0xff)
+				data->fan_step_output[i] =
+				  w83627ehf_read_value(data,
+						data->REG_FAN_STEP_OUTPUT[i]);
+
+			data->target_temp[i] =
+				w83627ehf_read_value(data,
+					data->REG_TARGET[i]) &
+					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
+		}
+
+		/* Measured temperatures and limits */
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			if (!(data->have_temp & (1 << i)))
+				continue;
+			data->temp[i] = w83627ehf_read_temp(data,
+						data->reg_temp[i]);
+			if (data->reg_temp_over[i])
+				data->temp_max[i]
+				  = w83627ehf_read_temp(data,
+						data->reg_temp_over[i]);
+			if (data->reg_temp_hyst[i])
+				data->temp_max_hyst[i]
+				  = w83627ehf_read_temp(data,
+						data->reg_temp_hyst[i]);
+			if (i > 2)
+				continue;
+			if (data->have_temp_offset & (1 << i))
+				data->temp_offset[i]
+				  = w83627ehf_read_value(data,
+						W83627EHF_REG_TEMP_OFFSET[i]);
+		}
+
+		data->alarms = w83627ehf_read_value(data,
+					W83627EHF_REG_ALARM1) |
+			       (w83627ehf_read_value(data,
+					W83627EHF_REG_ALARM2) << 8) |
+			       (w83627ehf_read_value(data,
+					W83627EHF_REG_ALARM3) << 16);
+
+		data->caseopen = w83627ehf_read_value(data,
+						W83627EHF_REG_CASEOPEN_DET);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+#define show_in_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+	   char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr, \
+		       data->scale_in)); \
+}
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define store_in_reg(REG, reg) \
+static ssize_t \
+store_in_##reg(struct device *dev, struct device_attribute *attr, \
+	       const char *buf, size_t count) \
+{ \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	unsigned long val; \
+	int err; \
+	err = kstrtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = in_to_reg(val, nr, data->scale_in); \
+	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
+			      data->in_##reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+store_in_reg(MIN, min)
+store_in_reg(MAX, max)
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
+}
+
+static struct sensor_device_attribute sda_in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+	SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+	SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+	SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+	SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+	SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+	SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+	SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
+	SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
+	SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
+	SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
+	SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", data->rpm[nr]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",
+		       data->fan_from_reg_min(data->fan_min[nr],
+					      data->fan_div[nr]));
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+	     char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	int err;
+	unsigned int reg;
+	u8 new_div;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (!data->has_fan_div) {
+		/*
+		 * Only NCT6776F for now, so we know that this is a 13 bit
+		 * register
+		 */
+		if (!val) {
+			val = 0xff1f;
+		} else {
+			if (val > 1350000U)
+				val = 135000U;
+			val = 1350000U / val;
+			val = (val & 0x1f) | ((val << 3) & 0xff00);
+		}
+		data->fan_min[nr] = val;
+		goto done;	/* Leave fan divider alone */
+	}
+	if (!val) {
+		/* No min limit, alarm disabled */
+		data->fan_min[nr] = 255;
+		new_div = data->fan_div[nr]; /* No change */
+		dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
+	} else if ((reg = 1350000U / val) >= 128 * 255) {
+		/*
+		 * Speed below this value cannot possibly be represented,
+		 * even with the highest divider (128)
+		 */
+		data->fan_min[nr] = 254;
+		new_div = 7; /* 128 == (1 << 7) */
+		dev_warn(dev,
+			 "fan%u low limit %lu below minimum %u, set to minimum\n",
+			 nr + 1, val, data->fan_from_reg_min(254, 7));
+	} else if (!reg) {
+		/*
+		 * Speed above this value cannot possibly be represented,
+		 * even with the lowest divider (1)
+		 */
+		data->fan_min[nr] = 1;
+		new_div = 0; /* 1 == (1 << 0) */
+		dev_warn(dev,
+			 "fan%u low limit %lu above maximum %u, set to maximum\n",
+			 nr + 1, val, data->fan_from_reg_min(1, 0));
+	} else {
+		/*
+		 * Automatically pick the best divider, i.e. the one such
+		 * that the min limit will correspond to a register value
+		 * in the 96..192 range
+		 */
+		new_div = 0;
+		while (reg > 192 && new_div < 7) {
+			reg >>= 1;
+			new_div++;
+		}
+		data->fan_min[nr] = reg;
+	}
+
+	/*
+	 * Write both the fan clock divider (if it changed) and the new
+	 * fan min (unconditionally)
+	 */
+	if (new_div != data->fan_div[nr]) {
+		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+			nr + 1, div_from_reg(data->fan_div[nr]),
+			div_from_reg(new_div));
+		data->fan_div[nr] = new_div;
+		w83627ehf_write_fan_div_common(dev, data, nr);
+		/* Give the chip time to sample a new speed value */
+		data->last_updated = jiffies;
+	}
+done:
+	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
+			      data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+	SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+	SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+	SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+	SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
+	SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 1),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 2),
+	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 3),
+	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 4),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+	SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
+	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
+#define show_temp_reg(addr, reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+	   char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->reg[nr])); \
+}
+show_temp_reg(reg_temp, temp);
+show_temp_reg(reg_temp_over, temp_max);
+show_temp_reg(reg_temp_hyst, temp_max_hyst);
+
+#define store_temp_reg(addr, reg) \
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+	    const char *buf, size_t count) \
+{ \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	int err; \
+	long val; \
+	err = kstrtol(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->reg[nr] = LM75_TEMP_TO_REG(val); \
+	w83627ehf_write_temp(data, data->addr[nr], data->reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+store_temp_reg(reg_temp_over, temp_max);
+store_temp_reg(reg_temp_hyst, temp_max_hyst);
+
+static ssize_t
+show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+
+	return sprintf(buf, "%d\n",
+		       data->temp_offset[sensor_attr->index] * 1000);
+}
+
+static ssize_t
+store_temp_offset(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp_offset[nr] = val;
+	w83627ehf_write_value(data, W83627EHF_REG_TEMP_OFFSET[nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
+static struct sensor_device_attribute sda_temp_input[] = {
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+	SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
+	SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
+	SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
+	SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
+	SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+	SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+	SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+	SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+	SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+	SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+	SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
+};
+
+static struct sensor_device_attribute sda_temp_max[] = {
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 0),
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 1),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 2),
+	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 3),
+	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 4),
+	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 5),
+	SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 6),
+	SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 7),
+	SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 8),
+};
+
+static struct sensor_device_attribute sda_temp_max_hyst[] = {
+	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 0),
+	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 1),
+	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 2),
+	SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 3),
+	SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 4),
+	SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 5),
+	SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 6),
+	SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 7),
+	SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 8),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+	SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+	SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+	SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
+	SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+	SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+	SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+};
+
+static struct sensor_device_attribute sda_temp_offset[] = {
+	SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+		    store_temp_offset, 0),
+	SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+		    store_temp_offset, 1),
+	SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+		    store_temp_offset, 2),
+};
+
+#define show_pwm_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			  char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", data->reg[nr]); \
+}
+
+show_pwm_reg(pwm_mode)
+show_pwm_reg(pwm_enable)
+show_pwm_reg(pwm)
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	int err;
+	u16 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	/* On NCT67766F, DC mode is only supported for pwm1 */
+	if (sio_data->kind == nct6776 && nr && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
+	data->pwm_mode[nr] = val;
+	reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
+	if (!val)
+		reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
+	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(val, 0, 255);
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = val;
+	w83627ehf_write_value(data, data->REG_PWM[nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	int err;
+	u16 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
+		return -EINVAL;
+	/* SmartFan III mode is not supported on NCT6776F */
+	if (sio_data->kind == nct6776 && val == 4)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable[nr] = val;
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		reg = w83627ehf_read_value(data,
+					   NCT6775_REG_FAN_MODE[nr]);
+		reg &= 0x0f;
+		reg |= (val - 1) << 4;
+		w83627ehf_write_value(data,
+				      NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
+		reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+		reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+		w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+#define show_tol_temp(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+				char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
+}
+
+show_tol_temp(tolerance)
+show_tol_temp(target_temp)
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
+
+	mutex_lock(&data->update_lock);
+	data->target_temp[nr] = val;
+	w83627ehf_write_value(data, data->REG_TARGET[nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	u16 reg;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* Limit the temp to 0C - 15C */
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
+
+	mutex_lock(&data->update_lock);
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		/* Limit tolerance further for NCT6776F */
+		if (sio_data->kind == nct6776 && val > 7)
+			val = 7;
+		reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
+		reg = (reg & 0xf0) | val;
+		w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
+		if (nr == 1)
+			reg = (reg & 0x0f) | (val << 4);
+		else
+			reg = (reg & 0xf0) | val;
+		w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+	}
+	data->tolerance[nr] = val;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+	SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_mode[] = {
+	SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 0),
+	SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 1),
+	SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 2),
+	SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_enable[] = {
+	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 0),
+	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 1),
+	SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 2),
+	SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 3),
+};
+
+static struct sensor_device_attribute sda_target_temp[] = {
+	SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
+		    store_target_temp, 0),
+	SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
+		    store_target_temp, 1),
+	SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
+		    store_target_temp, 2),
+	SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
+		    store_target_temp, 3),
+};
+
+static struct sensor_device_attribute sda_tolerance[] = {
+	SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+		    store_tolerance, 0),
+	SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+		    store_tolerance, 1),
+	SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+		    store_tolerance, 2),
+	SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+		    store_tolerance, 3),
+};
+
+/* Smart Fan registers */
+
+#define fan_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+		       char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", data->reg[nr]); \
+} \
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+			    const char *buf, size_t count) \
+{ \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	unsigned long val; \
+	int err; \
+	err = kstrtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = clamp_val(val, 1, 255); \
+	mutex_lock(&data->update_lock); \
+	data->reg[nr] = val; \
+	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+fan_functions(fan_start_output, FAN_START_OUTPUT)
+fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
+fan_functions(fan_max_output, FAN_MAX_OUTPUT)
+fan_functions(fan_step_output, FAN_STEP_OUTPUT)
+
+#define fan_time_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+				char *buf) \
+{ \
+	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", \
+			step_time_from_reg(data->reg[nr], \
+					   data->pwm_mode[nr])); \
+} \
+\
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+			const char *buf, size_t count) \
+{ \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	unsigned long val; \
+	int err; \
+	err = kstrtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = step_time_to_reg(val, data->pwm_mode[nr]); \
+	mutex_lock(&data->update_lock); \
+	data->reg[nr] = val; \
+	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+} \
+
+fan_time_functions(fan_stop_time, FAN_STOP_TIME)
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
+	SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+		    store_fan_stop_time, 3),
+	SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
+		    store_fan_start_output, 3),
+	SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
+		    store_fan_stop_output, 3),
+	SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
+		    store_fan_max_output, 3),
+	SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
+		    store_fan_step_output, 3),
+};
+
+static struct sensor_device_attribute sda_sf3_arrays_fan3[] = {
+	SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+		    store_fan_stop_time, 2),
+	SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
+		    store_fan_start_output, 2),
+	SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
+		    store_fan_stop_output, 2),
+};
+
+static struct sensor_device_attribute sda_sf3_arrays[] = {
+	SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+		    store_fan_stop_time, 0),
+	SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+		    store_fan_stop_time, 1),
+	SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
+		    store_fan_start_output, 0),
+	SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
+		    store_fan_start_output, 1),
+	SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
+		    store_fan_stop_output, 0),
+	SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
+		    store_fan_stop_output, 1),
+};
+
+
+/*
+ * pwm1 and pwm3 don't support max and step settings on all chips.
+ * Need to check support while generating/removing attribute files.
+ */
+static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
+	SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
+		    store_fan_max_output, 0),
+	SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
+		    store_fan_step_output, 0),
+	SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
+		    store_fan_max_output, 1),
+	SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
+		    store_fan_step_output, 1),
+	SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
+		    store_fan_max_output, 2),
+	SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
+		    store_fan_step_output, 2),
+};
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+
+/* Case open detection */
+
+static ssize_t
+show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		!!(data->caseopen & to_sensor_dev_attr_2(attr)->index));
+}
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u16 reg, mask;
+
+	if (kstrtoul(buf, 10, &val) || val != 0)
+		return -EINVAL;
+
+	mask = to_sensor_dev_attr_2(attr)->nr;
+
+	mutex_lock(&data->update_lock);
+	reg = w83627ehf_read_value(data, W83627EHF_REG_CASEOPEN_CLR);
+	w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg | mask);
+	w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg & ~mask);
+	data->valid = 0;	/* Force cache refresh */
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute_2 sda_caseopen[] = {
+	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+			clear_caseopen, 0x80, 0x10),
+	SENSOR_ATTR_2(intrusion1_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+			clear_caseopen, 0x40, 0x40),
+};
+
+/*
+ * Driver and device management
+ */
+
+static void w83627ehf_device_remove_files(struct device *dev)
+{
+	/*
+	 * some entries in the following arrays may not have been used in
+	 * device_create_file(), but device_remove_file() will ignore them
+	 */
+	int i;
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
+		device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
+		struct sensor_device_attribute *attr =
+		  &sda_sf3_max_step_arrays[i];
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
+			device_remove_file(dev, &attr->dev_attr);
+	}
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan3); i++)
+		device_remove_file(dev, &sda_sf3_arrays_fan3[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
+		device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
+	for (i = 0; i < data->in_num; i++) {
+		if ((i == 6) && data->in6_skip)
+			continue;
+		device_remove_file(dev, &sda_in_input[i].dev_attr);
+		device_remove_file(dev, &sda_in_alarm[i].dev_attr);
+		device_remove_file(dev, &sda_in_min[i].dev_attr);
+		device_remove_file(dev, &sda_in_max[i].dev_attr);
+	}
+	for (i = 0; i < 5; i++) {
+		device_remove_file(dev, &sda_fan_input[i].dev_attr);
+		device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
+		device_remove_file(dev, &sda_fan_div[i].dev_attr);
+		device_remove_file(dev, &sda_fan_min[i].dev_attr);
+	}
+	for (i = 0; i < data->pwm_num; i++) {
+		device_remove_file(dev, &sda_pwm[i].dev_attr);
+		device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
+		device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
+		device_remove_file(dev, &sda_target_temp[i].dev_attr);
+		device_remove_file(dev, &sda_tolerance[i].dev_attr);
+	}
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		device_remove_file(dev, &sda_temp_input[i].dev_attr);
+		device_remove_file(dev, &sda_temp_label[i].dev_attr);
+		if (i == 2 && data->temp3_val_only)
+			continue;
+		device_remove_file(dev, &sda_temp_max[i].dev_attr);
+		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+		if (i > 2)
+			continue;
+		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
+		device_remove_file(dev, &sda_temp_type[i].dev_attr);
+		device_remove_file(dev, &sda_temp_offset[i].dev_attr);
+	}
+
+	device_remove_file(dev, &sda_caseopen[0].dev_attr);
+	device_remove_file(dev, &sda_caseopen[1].dev_attr);
+
+	device_remove_file(dev, &dev_attr_name);
+	device_remove_file(dev, &dev_attr_cpu0_vid);
+}
+
+/* Get the monitoring functions started */
+static inline void w83627ehf_init_device(struct w83627ehf_data *data,
+						   enum kinds kind)
+{
+	int i;
+	u8 tmp, diode;
+
+	/* Start monitoring is needed */
+	tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
+	if (!(tmp & 0x01))
+		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
+				      tmp | 0x01);
+
+	/* Enable temperature sensors if needed */
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		if (!data->reg_temp_config[i])
+			continue;
+		tmp = w83627ehf_read_value(data,
+					   data->reg_temp_config[i]);
+		if (tmp & 0x01)
+			w83627ehf_write_value(data,
+					      data->reg_temp_config[i],
+					      tmp & 0xfe);
+	}
+
+	/* Enable VBAT monitoring if needed */
+	tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+	if (!(tmp & 0x01))
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
+
+	/* Get thermal sensor types */
+	switch (kind) {
+	case w83627ehf:
+		diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+		break;
+	case w83627uhg:
+		diode = 0x00;
+		break;
+	default:
+		diode = 0x70;
+	}
+	for (i = 0; i < 3; i++) {
+		const char *label = NULL;
+
+		if (data->temp_label)
+			label = data->temp_label[data->temp_src[i]];
+
+		/* Digital source overrides analog type */
+		if (label && strncmp(label, "PECI", 4) == 0)
+			data->temp_type[i] = 6;
+		else if (label && strncmp(label, "AMD", 3) == 0)
+			data->temp_type[i] = 5;
+		else if ((tmp & (0x02 << i)))
+			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
+		else
+			data->temp_type[i] = 4; /* thermistor */
+	}
+}
+
+static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
+				   int r1, int r2)
+{
+	swap(data->temp_src[r1], data->temp_src[r2]);
+	swap(data->reg_temp[r1], data->reg_temp[r2]);
+	swap(data->reg_temp_over[r1], data->reg_temp_over[r2]);
+	swap(data->reg_temp_hyst[r1], data->reg_temp_hyst[r2]);
+	swap(data->reg_temp_config[r1], data->reg_temp_config[r2]);
+}
+
+static void
+w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp)
+{
+	int i;
+
+	for (i = 0; i < n_temp; i++) {
+		data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+		data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+		data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+		data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+	}
+}
+
+static void
+w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
+			   struct w83627ehf_data *data)
+{
+	int fan3pin, fan4pin, fan4min, fan5pin, regval;
+
+	/* The W83627UHG is simple, only two fan inputs, no config */
+	if (sio_data->kind == w83627uhg) {
+		data->has_fan = 0x03; /* fan1 and fan2 */
+		data->has_fan_min = 0x03;
+		return;
+	}
+
+	superio_enter(sio_data->sioreg);
+
+	/* fan4 and fan5 share some pins with the GPIO and serial flash */
+	if (sio_data->kind == nct6775) {
+		/* On NCT6775, fan4 shares pins with the fdc interface */
+		fan3pin = 1;
+		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+		fan4min = 0;
+		fan5pin = 0;
+	} else if (sio_data->kind == nct6776) {
+		bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+
+		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+		regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+
+		if (regval & 0x80)
+			fan3pin = gpok;
+		else
+			fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+
+		if (regval & 0x40)
+			fan4pin = gpok;
+		else
+			fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
+
+		if (regval & 0x20)
+			fan5pin = gpok;
+		else
+			fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+
+		fan4min = fan4pin;
+	} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+		fan3pin = 1;
+		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+		fan4min = fan4pin;
+	} else {
+		fan3pin = 1;
+		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+		fan4min = fan4pin;
+	}
+
+	superio_exit(sio_data->sioreg);
+
+	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+	data->has_fan |= (fan3pin << 2);
+	data->has_fan_min |= (fan3pin << 2);
+
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		/*
+		 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1
+		 * register
+		 */
+		data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+		data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+	} else {
+		/*
+		 * It looks like fan4 and fan5 pins can be alternatively used
+		 * as fan on/off switches, but fan5 control is write only :/
+		 * We assume that if the serial interface is disabled, designers
+		 * connected fan5 as input unless they are emitting log 1, which
+		 * is not the default.
+		 */
+		regval = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+		if ((regval & (1 << 2)) && fan4pin) {
+			data->has_fan |= (1 << 3);
+			data->has_fan_min |= (1 << 3);
+		}
+		if (!(regval & (1 << 1)) && fan5pin) {
+			data->has_fan |= (1 << 4);
+			data->has_fan_min |= (1 << 4);
+		}
+	}
+}
+
+static int w83627ehf_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+	struct w83627ehf_data *data;
+	struct resource *res;
+	u8 en_vrm10;
+	int i, err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
+		err = -EBUSY;
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)res->start + IOREGION_LENGTH - 1);
+		goto exit;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct w83627ehf_data),
+			    GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+
+	data->addr = res->start;
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+	data->name = w83627ehf_device_names[sio_data->kind];
+	data->bank = 0xff;		/* Force initial bank selection */
+	platform_set_drvdata(pdev, data);
+
+	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
+	data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
+	/* 667HG, NCT6775F, and NCT6776F have 3 pwms, and 627UHG has only 2 */
+	switch (sio_data->kind) {
+	default:
+		data->pwm_num = 4;
+		break;
+	case w83667hg:
+	case w83667hg_b:
+	case nct6775:
+	case nct6776:
+		data->pwm_num = 3;
+		break;
+	case w83627uhg:
+		data->pwm_num = 2;
+		break;
+	}
+
+	/* Default to 3 temperature inputs, code below will adjust as needed */
+	data->have_temp = 0x07;
+
+	/* Deal with temperature register setup first. */
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		int mask = 0;
+
+		/*
+		 * Display temperature sensor output only if it monitors
+		 * a source other than one already reported. Always display
+		 * first three temperature registers, though.
+		 */
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			u8 src;
+
+			data->reg_temp[i] = NCT6775_REG_TEMP[i];
+			data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
+
+			src = w83627ehf_read_value(data,
+						   NCT6775_REG_TEMP_SOURCE[i]);
+			src &= 0x1f;
+			if (src && !(mask & (1 << src))) {
+				data->have_temp |= 1 << i;
+				mask |= 1 << src;
+			}
+
+			data->temp_src[i] = src;
+
+			/*
+			 * Now do some register swapping if index 0..2 don't
+			 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
+			 * Idea is to have the first three attributes
+			 * report SYSTIN, CPUIN, and AUXIN if possible
+			 * without overriding the basic system configuration.
+			 */
+			if (i > 0 && data->temp_src[0] != 1
+			    && data->temp_src[i] == 1)
+				w82627ehf_swap_tempreg(data, 0, i);
+			if (i > 1 && data->temp_src[1] != 2
+			    && data->temp_src[i] == 2)
+				w82627ehf_swap_tempreg(data, 1, i);
+			if (i > 2 && data->temp_src[2] != 3
+			    && data->temp_src[i] == 3)
+				w82627ehf_swap_tempreg(data, 2, i);
+		}
+		if (sio_data->kind == nct6776) {
+			/*
+			 * On NCT6776, AUXTIN and VIN3 pins are shared.
+			 * Only way to detect it is to check if AUXTIN is used
+			 * as a temperature source, and if that source is
+			 * enabled.
+			 *
+			 * If that is the case, disable in6, which reports VIN3.
+			 * Otherwise disable temp3.
+			 */
+			if (data->temp_src[2] == 3) {
+				u8 reg;
+
+				if (data->reg_temp_config[2])
+					reg = w83627ehf_read_value(data,
+						data->reg_temp_config[2]);
+				else
+					reg = 0; /* Assume AUXTIN is used */
+
+				if (reg & 0x01)
+					data->have_temp &= ~(1 << 2);
+				else
+					data->in6_skip = 1;
+			}
+			data->temp_label = nct6776_temp_label;
+		} else {
+			data->temp_label = nct6775_temp_label;
+		}
+		data->have_temp_offset = data->have_temp & 0x07;
+		for (i = 0; i < 3; i++) {
+			if (data->temp_src[i] > 3)
+				data->have_temp_offset &= ~(1 << i);
+		}
+	} else if (sio_data->kind == w83667hg_b) {
+		u8 reg;
+
+		w83627ehf_set_temp_reg_ehf(data, 4);
+
+		/*
+		 * Temperature sources are selected with bank 0, registers 0x49
+		 * and 0x4a.
+		 */
+		reg = w83627ehf_read_value(data, 0x4a);
+		data->temp_src[0] = reg >> 5;
+		reg = w83627ehf_read_value(data, 0x49);
+		data->temp_src[1] = reg & 0x07;
+		data->temp_src[2] = (reg >> 4) & 0x07;
+
+		/*
+		 * W83667HG-B has another temperature register at 0x7e.
+		 * The temperature source is selected with register 0x7d.
+		 * Support it if the source differs from already reported
+		 * sources.
+		 */
+		reg = w83627ehf_read_value(data, 0x7d);
+		reg &= 0x07;
+		if (reg != data->temp_src[0] && reg != data->temp_src[1]
+		    && reg != data->temp_src[2]) {
+			data->temp_src[3] = reg;
+			data->have_temp |= 1 << 3;
+		}
+
+		/*
+		 * Chip supports either AUXTIN or VIN3. Try to find out which
+		 * one.
+		 */
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+		if (data->temp_src[2] == 2 && (reg & 0x01))
+			data->have_temp &= ~(1 << 2);
+
+		if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
+		    || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
+			data->in6_skip = 1;
+
+		data->temp_label = w83667hg_b_temp_label;
+		data->have_temp_offset = data->have_temp & 0x07;
+		for (i = 0; i < 3; i++) {
+			if (data->temp_src[i] > 2)
+				data->have_temp_offset &= ~(1 << i);
+		}
+	} else if (sio_data->kind == w83627uhg) {
+		u8 reg;
+
+		w83627ehf_set_temp_reg_ehf(data, 3);
+
+		/*
+		 * Temperature sources for temp2 and temp3 are selected with
+		 * bank 0, registers 0x49 and 0x4a.
+		 */
+		data->temp_src[0] = 0;	/* SYSTIN */
+		reg = w83627ehf_read_value(data, 0x49) & 0x07;
+		/* Adjust to have the same mapping as other source registers */
+		if (reg == 0)
+			data->temp_src[1] = 1;
+		else if (reg >= 2 && reg <= 5)
+			data->temp_src[1] = reg + 2;
+		else	/* should never happen */
+			data->have_temp &= ~(1 << 1);
+		reg = w83627ehf_read_value(data, 0x4a);
+		data->temp_src[2] = reg >> 5;
+
+		/*
+		 * Skip temp3 if source is invalid or the same as temp1
+		 * or temp2.
+		 */
+		if (data->temp_src[2] == 2 || data->temp_src[2] == 3 ||
+		    data->temp_src[2] == data->temp_src[0] ||
+		    ((data->have_temp & (1 << 1)) &&
+		     data->temp_src[2] == data->temp_src[1]))
+			data->have_temp &= ~(1 << 2);
+		else
+			data->temp3_val_only = 1;	/* No limit regs */
+
+		data->in6_skip = 1;			/* No VIN3 */
+
+		data->temp_label = w83667hg_b_temp_label;
+		data->have_temp_offset = data->have_temp & 0x03;
+		for (i = 0; i < 3; i++) {
+			if (data->temp_src[i] > 1)
+				data->have_temp_offset &= ~(1 << i);
+		}
+	} else {
+		w83627ehf_set_temp_reg_ehf(data, 3);
+
+		/* Temperature sources are fixed */
+
+		if (sio_data->kind == w83667hg) {
+			u8 reg;
+
+			/*
+			 * Chip supports either AUXTIN or VIN3. Try to find
+			 * out which one.
+			 */
+			reg = w83627ehf_read_value(data,
+						W83627EHF_REG_TEMP_CONFIG[2]);
+			if (reg & 0x01)
+				data->have_temp &= ~(1 << 2);
+			else
+				data->in6_skip = 1;
+		}
+		data->have_temp_offset = data->have_temp & 0x07;
+	}
+
+	if (sio_data->kind == nct6775) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg16;
+		data->fan_from_reg_min = fan_from_reg8;
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6775_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
+		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
+	} else if (sio_data->kind == nct6776) {
+		data->has_fan_div = false;
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6775_REG_FAN;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+	} else if (sio_data->kind == w83667hg_b) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
+		data->REG_FAN_MAX_OUTPUT =
+		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
+		data->REG_FAN_STEP_OUTPUT =
+		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
+	} else {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
+		data->REG_FAN_MAX_OUTPUT =
+		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
+		data->REG_FAN_STEP_OUTPUT =
+		  W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
+	}
+
+	/* Setup input voltage scaling factors */
+	if (sio_data->kind == w83627uhg)
+		data->scale_in = scale_in_w83627uhg;
+	else
+		data->scale_in = scale_in_common;
+
+	/* Initialize the chip */
+	w83627ehf_init_device(data, sio_data->kind);
+
+	data->vrm = vid_which_vrm();
+	superio_enter(sio_data->sioreg);
+	/* Read VID value */
+	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
+	    sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		/*
+		 * W83667HG has different pins for VID input and output, so
+		 * we can get the VID input values directly at logical device D
+		 * 0xe3.
+		 */
+		superio_select(sio_data->sioreg, W83667HG_LD_VID);
+		data->vid = superio_inb(sio_data->sioreg, 0xe3);
+		err = device_create_file(dev, &dev_attr_cpu0_vid);
+		if (err)
+			goto exit_release;
+	} else if (sio_data->kind != w83627uhg) {
+		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+		if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
+			/*
+			 * Set VID input sensibility if needed. In theory the
+			 * BIOS should have set it, but in practice it's not
+			 * always the case. We only do it for the W83627EHF/EHG
+			 * because the W83627DHG is more complex in this
+			 * respect.
+			 */
+			if (sio_data->kind == w83627ehf) {
+				en_vrm10 = superio_inb(sio_data->sioreg,
+						       SIO_REG_EN_VRM10);
+				if ((en_vrm10 & 0x08) && data->vrm == 90) {
+					dev_warn(dev,
+						 "Setting VID input voltage to TTL\n");
+					superio_outb(sio_data->sioreg,
+						     SIO_REG_EN_VRM10,
+						     en_vrm10 & ~0x08);
+				} else if (!(en_vrm10 & 0x08)
+					   && data->vrm == 100) {
+					dev_warn(dev,
+						 "Setting VID input voltage to VRM10\n");
+					superio_outb(sio_data->sioreg,
+						     SIO_REG_EN_VRM10,
+						     en_vrm10 | 0x08);
+				}
+			}
+
+			data->vid = superio_inb(sio_data->sioreg,
+						SIO_REG_VID_DATA);
+			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
+				data->vid &= 0x3f;
+
+			err = device_create_file(dev, &dev_attr_cpu0_vid);
+			if (err)
+				goto exit_release;
+		} else {
+			dev_info(dev,
+				 "VID pins in output mode, CPU VID not available\n");
+		}
+	}
+
+	if (fan_debounce &&
+	    (sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
+		u8 tmp;
+
+		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+		tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE);
+		if (sio_data->kind == nct6776)
+			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
+				     0x3e | tmp);
+		else
+			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
+				     0x1e | tmp);
+		pr_info("Enabled fan debounce for chip %s\n", data->name);
+	}
+
+	superio_exit(sio_data->sioreg);
+
+	w83627ehf_check_fan_inputs(sio_data, data);
+
+	/* Read fan clock dividers immediately */
+	w83627ehf_update_fan_div_common(dev, data);
+
+	/* Read pwm data to save original values */
+	w83627ehf_update_pwm_common(dev, data);
+	for (i = 0; i < data->pwm_num; i++)
+		data->pwm_enable_orig[i] = data->pwm_enable[i];
+
+	/* Register sysfs hooks */
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
+		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
+		struct sensor_device_attribute *attr =
+		  &sda_sf3_max_step_arrays[i];
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
+			err = device_create_file(dev, &attr->dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+	/* if fan3 and fan4 are enabled create the sf3 files for them */
+	if ((data->has_fan & (1 << 2)) && data->pwm_num >= 3)
+		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan3); i++) {
+			err = device_create_file(dev,
+					&sda_sf3_arrays_fan3[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
+		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
+			err = device_create_file(dev,
+					&sda_sf3_arrays_fan4[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+
+	for (i = 0; i < data->in_num; i++) {
+		if ((i == 6) && data->in6_skip)
+			continue;
+		if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
+			|| (err = device_create_file(dev,
+				&sda_in_alarm[i].dev_attr))
+			|| (err = device_create_file(dev,
+				&sda_in_min[i].dev_attr))
+			|| (err = device_create_file(dev,
+				&sda_in_max[i].dev_attr)))
+			goto exit_remove;
+	}
+
+	for (i = 0; i < 5; i++) {
+		if (data->has_fan & (1 << i)) {
+			if ((err = device_create_file(dev,
+					&sda_fan_input[i].dev_attr))
+				|| (err = device_create_file(dev,
+					&sda_fan_alarm[i].dev_attr)))
+				goto exit_remove;
+			if (sio_data->kind != nct6776) {
+				err = device_create_file(dev,
+						&sda_fan_div[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
+			if (data->has_fan_min & (1 << i)) {
+				err = device_create_file(dev,
+						&sda_fan_min[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
+			if (i < data->pwm_num &&
+				((err = device_create_file(dev,
+					&sda_pwm[i].dev_attr))
+				|| (err = device_create_file(dev,
+					&sda_pwm_mode[i].dev_attr))
+				|| (err = device_create_file(dev,
+					&sda_pwm_enable[i].dev_attr))
+				|| (err = device_create_file(dev,
+					&sda_target_temp[i].dev_attr))
+				|| (err = device_create_file(dev,
+					&sda_tolerance[i].dev_attr))))
+				goto exit_remove;
+		}
+	}
+
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+		if (err)
+			goto exit_remove;
+		if (data->temp_label) {
+			err = device_create_file(dev,
+						 &sda_temp_label[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (i == 2 && data->temp3_val_only)
+			continue;
+		if (data->reg_temp_over[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (data->reg_temp_hyst[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max_hyst[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (i > 2)
+			continue;
+		if ((err = device_create_file(dev,
+				&sda_temp_alarm[i].dev_attr))
+			|| (err = device_create_file(dev,
+				&sda_temp_type[i].dev_attr)))
+			goto exit_remove;
+		if (data->have_temp_offset & (1 << i)) {
+			err = device_create_file(dev,
+						 &sda_temp_offset[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	err = device_create_file(dev, &sda_caseopen[0].dev_attr);
+	if (err)
+		goto exit_remove;
+
+	if (sio_data->kind == nct6776) {
+		err = device_create_file(dev, &sda_caseopen[1].dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+
+	err = device_create_file(dev, &dev_attr_name);
+	if (err)
+		goto exit_remove;
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	w83627ehf_device_remove_files(dev);
+exit_release:
+	release_region(res->start, IOREGION_LENGTH);
+exit:
+	return err;
+}
+
+static int w83627ehf_remove(struct platform_device *pdev)
+{
+	struct w83627ehf_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	w83627ehf_device_remove_files(&pdev->dev);
+	release_region(data->addr, IOREGION_LENGTH);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int w83627ehf_suspend(struct device *dev)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+
+	mutex_lock(&data->update_lock);
+	data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+	if (sio_data->kind == nct6775) {
+		data->fandiv1 = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+		data->fandiv2 = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static int w83627ehf_resume(struct device *dev)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
+	int i;
+
+	mutex_lock(&data->update_lock);
+	data->bank = 0xff;		/* Force initial bank selection */
+
+	/* Restore limits */
+	for (i = 0; i < data->in_num; i++) {
+		if ((i == 6) && data->in6_skip)
+			continue;
+
+		w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i),
+				      data->in_min[i]);
+		w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i),
+				      data->in_max[i]);
+	}
+
+	for (i = 0; i < 5; i++) {
+		if (!(data->has_fan_min & (1 << i)))
+			continue;
+
+		w83627ehf_write_value(data, data->REG_FAN_MIN[i],
+				      data->fan_min[i]);
+	}
+
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+
+		if (data->reg_temp_over[i])
+			w83627ehf_write_temp(data, data->reg_temp_over[i],
+					     data->temp_max[i]);
+		if (data->reg_temp_hyst[i])
+			w83627ehf_write_temp(data, data->reg_temp_hyst[i],
+					     data->temp_max_hyst[i]);
+		if (i > 2)
+			continue;
+		if (data->have_temp_offset & (1 << i))
+			w83627ehf_write_value(data,
+					      W83627EHF_REG_TEMP_OFFSET[i],
+					      data->temp_offset[i]);
+	}
+
+	/* Restore other settings */
+	w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat);
+	if (sio_data->kind == nct6775) {
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
+	}
+
+	/* Force re-reading all values */
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops w83627ehf_dev_pm_ops = {
+	.suspend = w83627ehf_suspend,
+	.resume = w83627ehf_resume,
+	.freeze = w83627ehf_suspend,
+	.restore = w83627ehf_resume,
+};
+
+#define W83627EHF_DEV_PM_OPS	(&w83627ehf_dev_pm_ops)
+#else
+#define W83627EHF_DEV_PM_OPS	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver w83627ehf_driver = {
+	.driver = {
+		.name	= DRVNAME,
+		.pm	= W83627EHF_DEV_PM_OPS,
+	},
+	.probe		= w83627ehf_probe,
+	.remove		= w83627ehf_remove,
+};
+
+/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
+				 struct w83627ehf_sio_data *sio_data)
+{
+	static const char sio_name_W83627EHF[] __initconst = "W83627EHF";
+	static const char sio_name_W83627EHG[] __initconst = "W83627EHG";
+	static const char sio_name_W83627DHG[] __initconst = "W83627DHG";
+	static const char sio_name_W83627DHG_P[] __initconst = "W83627DHG-P";
+	static const char sio_name_W83627UHG[] __initconst = "W83627UHG";
+	static const char sio_name_W83667HG[] __initconst = "W83667HG";
+	static const char sio_name_W83667HG_B[] __initconst = "W83667HG-B";
+	static const char sio_name_NCT6775[] __initconst = "NCT6775F";
+	static const char sio_name_NCT6776[] __initconst = "NCT6776F";
+
+	u16 val;
+	const char *sio_name;
+
+	superio_enter(sioaddr);
+
+	if (force_id)
+		val = force_id;
+	else
+		val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+		    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+	switch (val & SIO_ID_MASK) {
+	case SIO_W83627EHF_ID:
+		sio_data->kind = w83627ehf;
+		sio_name = sio_name_W83627EHF;
+		break;
+	case SIO_W83627EHG_ID:
+		sio_data->kind = w83627ehf;
+		sio_name = sio_name_W83627EHG;
+		break;
+	case SIO_W83627DHG_ID:
+		sio_data->kind = w83627dhg;
+		sio_name = sio_name_W83627DHG;
+		break;
+	case SIO_W83627DHG_P_ID:
+		sio_data->kind = w83627dhg_p;
+		sio_name = sio_name_W83627DHG_P;
+		break;
+	case SIO_W83627UHG_ID:
+		sio_data->kind = w83627uhg;
+		sio_name = sio_name_W83627UHG;
+		break;
+	case SIO_W83667HG_ID:
+		sio_data->kind = w83667hg;
+		sio_name = sio_name_W83667HG;
+		break;
+	case SIO_W83667HG_B_ID:
+		sio_data->kind = w83667hg_b;
+		sio_name = sio_name_W83667HG_B;
+		break;
+	case SIO_NCT6775_ID:
+		sio_data->kind = nct6775;
+		sio_name = sio_name_NCT6775;
+		break;
+	case SIO_NCT6776_ID:
+		sio_data->kind = nct6776;
+		sio_name = sio_name_NCT6776;
+		break;
+	default:
+		if (val != 0xffff)
+			pr_debug("unsupported chip ID: 0x%04x\n", val);
+		superio_exit(sioaddr);
+		return -ENODEV;
+	}
+
+	/* We have a known chip, find the HWM I/O address */
+	superio_select(sioaddr, W83627EHF_LD_HWM);
+	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+	*addr = val & IOREGION_ALIGNMENT;
+	if (*addr == 0) {
+		pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
+		superio_exit(sioaddr);
+		return -ENODEV;
+	}
+
+	/* Activate logical device if needed */
+	val = superio_inb(sioaddr, SIO_REG_ENABLE);
+	if (!(val & 0x01)) {
+		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+	}
+
+	superio_exit(sioaddr);
+	pr_info("Found %s chip at %#x\n", sio_name, *addr);
+	sio_data->sioreg = sioaddr;
+
+	return 0;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the w83627ehf driver. But since we platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev;
+
+static int __init sensors_w83627ehf_init(void)
+{
+	int err;
+	unsigned short address;
+	struct resource res;
+	struct w83627ehf_sio_data sio_data;
+
+	/*
+	 * initialize sio_data->kind and sio_data->sioreg.
+	 *
+	 * when Super-I/O functions move to a separate file, the Super-I/O
+	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+	 * w83627ehf hardware monitor, and call probe()
+	 */
+	if (w83627ehf_find(0x2e, &address, &sio_data) &&
+	    w83627ehf_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	err = platform_driver_register(&w83627ehf_driver);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit_unregister;
+	}
+
+	err = platform_device_add_data(pdev, &sio_data,
+				       sizeof(struct w83627ehf_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	memset(&res, 0, sizeof(res));
+	res.name = DRVNAME;
+	res.start = address + IOREGION_OFFSET;
+	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+	res.flags = IORESOURCE_IO;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit_device_put;
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	/* platform_device_add calls probe() */
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit_unregister:
+	platform_driver_unregister(&w83627ehf_driver);
+exit:
+	return err;
+}
+
+static void __exit sensors_w83627ehf_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&w83627ehf_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("W83627EHF driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83627ehf_init);
+module_exit(sensors_w83627ehf_exit);
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
new file mode 100644
index 0000000..721295b
--- /dev/null
+++ b/drivers/hwmon/w83627hf.c
@@ -0,0 +1,2008 @@
+/*
+ * w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
+ *		monitoring
+ * Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *			      Philip Edelbrock <phil@netroedge.com>,
+ *			      and Mark Studebaker <mdsxyz123@yahoo.com>
+ * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ * Copyright (c) 2007 - 1012  Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)
+ * w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
+ * w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)
+ * w83687thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
+ * w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)
+ *
+ * For other winbond chips, and for i2c support in the above chips,
+ * use w83781d.c.
+ *
+ * Note: automatic ("cruise") fan control for 697, 637 & 627thf not
+ * supported yet.
+ */
+
+#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/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include "lm75.h"
+
+static struct platform_device *pdev;
+
+#define DRVNAME "w83627hf"
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+
+struct w83627hf_sio_data {
+	enum chips type;
+	int sioaddr;
+};
+
+static u8 force_i2c = 0x1f;
+module_param(force_i2c, byte, 0);
+MODULE_PARM_DESC(force_i2c,
+		 "Initialize the i2c address of the sensors");
+
+static bool init = 1;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/* modified from kernel/include/traps.c */
+#define DEV			0x07 /* Register: Logical device select */
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define DEVID			0x20 /* Register: Device ID */
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+static inline void
+superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int
+superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void
+superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	outb(DEV, sio->sioaddr);
+	outb(ld,  sio->sioaddr + 1);
+}
+
+static inline void
+superio_enter(struct w83627hf_sio_data *sio)
+{
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void
+superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+}
+
+#define W627_DEVID 0x52
+#define W627THF_DEVID 0x82
+#define W697_DEVID 0x60
+#define W637_DEVID 0x70
+#define W687THF_DEVID 0x85
+#define WINB_ACT_REG 0x30
+#define WINB_BASE_REG 0x60
+/* Constants specified below */
+
+/* Alignment of the base address */
+#define WINB_ALIGNMENT		~7
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET	5
+#define WINB_REGION_SIZE	2
+
+/* Where are the sensors address/data registers relative to the region offset */
+#define W83781D_ADDR_REG_OFFSET 0
+#define W83781D_DATA_REG_OFFSET 1
+
+/* The W83781D registers */
+/* The W83782D registers for nr=7,8 are in bank 5 */
+#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
+					   (0x554 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
+					   (0x555 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
+					   (0x550 + (nr) - 7))
+
+/* nr:0-2 for fans:1-3 */
+#define W83627HF_REG_FAN_MIN(nr)	(0x3b + (nr))
+#define W83627HF_REG_FAN(nr)		(0x28 + (nr))
+
+#define W83627HF_REG_TEMP2_CONFIG 0x152
+#define W83627HF_REG_TEMP3_CONFIG 0x252
+/* these are zero-based, unlike config constants above */
+static const u16 w83627hf_reg_temp[]		= { 0x27, 0x150, 0x250 };
+static const u16 w83627hf_reg_temp_hyst[]	= { 0x3A, 0x153, 0x253 };
+static const u16 w83627hf_reg_temp_over[]	= { 0x39, 0x155, 0x255 };
+
+#define W83781D_REG_BANK 0x4E
+
+#define W83781D_REG_CONFIG 0x40
+#define W83781D_REG_ALARM1 0x459
+#define W83781D_REG_ALARM2 0x45A
+#define W83781D_REG_ALARM3 0x45B
+
+#define W83781D_REG_BEEP_CONFIG 0x4D
+#define W83781D_REG_BEEP_INTS1 0x56
+#define W83781D_REG_BEEP_INTS2 0x57
+#define W83781D_REG_BEEP_INTS3 0x453
+
+#define W83781D_REG_VID_FANDIV 0x47
+
+#define W83781D_REG_CHIPID 0x49
+#define W83781D_REG_WCHIPID 0x58
+#define W83781D_REG_CHIPMAN 0x4F
+#define W83781D_REG_PIN 0x4B
+
+#define W83781D_REG_VBAT 0x5D
+
+#define W83627HF_REG_PWM1 0x5A
+#define W83627HF_REG_PWM2 0x5B
+
+static const u8 W83627THF_REG_PWM_ENABLE[] = {
+	0x04,		/* FAN 1 mode */
+	0x04,		/* FAN 2 mode */
+	0x12,		/* FAN AUX mode */
+};
+static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
+
+#define W83627THF_REG_PWM1		0x01	/* 697HF/637HF/687THF too */
+#define W83627THF_REG_PWM2		0x03	/* 697HF/637HF/687THF too */
+#define W83627THF_REG_PWM3		0x11	/* 637HF/687THF too */
+
+#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF/687THF too */
+
+static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
+static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
+                             W83627THF_REG_PWM3 };
+#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
+				    regpwm_627hf[nr] : regpwm[nr])
+
+#define W83627HF_REG_PWM_FREQ		0x5C	/* Only for the 627HF */
+
+#define W83637HF_REG_PWM_FREQ1		0x00	/* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ2		0x02	/* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ3		0x10	/* 687THF too */
+
+static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
+					W83637HF_REG_PWM_FREQ2,
+					W83637HF_REG_PWM_FREQ3 };
+
+#define W83627HF_BASE_PWM_FREQ	46870
+
+#define W83781D_REG_I2C_ADDR 0x48
+#define W83781D_REG_I2C_SUBADDR 0x4A
+
+/* Sensor selection */
+#define W83781D_REG_SCFG1 0x5D
+static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
+#define W83781D_REG_SCFG2 0x59
+static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
+#define W83781D_DEFAULT_BETA 3435
+
+/*
+ * Conversions. Limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ * Fixing this is just not worth it.
+ */
+#define IN_TO_REG(val)  (clamp_val((((val) + 8) / 16), 0, 255))
+#define IN_FROM_REG(val) ((val) * 16)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define TEMP_MIN (-128000)
+#define TEMP_MAX ( 127000)
+
+/*
+ * TEMP: 0.001C/bit (-128C to +127C)
+ * REG: 1C/bit, two's complement
+ */
+static u8 TEMP_TO_REG(long temp)
+{
+	int ntemp = clamp_val(temp, TEMP_MIN, TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
+}
+
+static int TEMP_FROM_REG(u8 reg)
+{
+        return (s8)reg * 1000;
+}
+
+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
+
+#define PWM_TO_REG(val) (clamp_val((val), 0, 255))
+
+static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
+{
+	unsigned long freq;
+	freq = W83627HF_BASE_PWM_FREQ >> reg;
+	return freq;
+}
+static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
+{
+	u8 i;
+	/*
+	 * Only 5 dividers (1 2 4 8 16)
+	 * Search for the nearest available frequency
+	 */
+	for (i = 0; i < 4; i++) {
+		if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
+			    (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
+			break;
+	}
+	return i;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+	/* Clock bit 8 -> 180 kHz or 24 MHz */
+	unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
+
+	reg &= 0x7f;
+	/* This should not happen but anyway... */
+	if (reg == 0)
+		reg++;
+	return clock / (reg << 8);
+}
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+	/* Minimum divider value is 0x01 and maximum is 0x7F */
+	if (val >= 93750)	/* The highest we can do */
+		return 0x01;
+	if (val >= 720)	/* Use 24 MHz clock */
+		return 24000000UL / (val << 8);
+	if (val < 6)		/* The lowest we can do */
+		return 0xFF;
+	else			/* Use 180 kHz clock */
+		return 0x80 | (180000UL / (val << 8));
+}
+
+#define BEEP_MASK_FROM_REG(val)		((val) & 0xff7fff)
+#define BEEP_MASK_TO_REG(val)		((val) & 0xff7fff)
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+static inline u8 DIV_TO_REG(long val)
+{
+	int i;
+	val = clamp_val(val, 1, 128) >> 1;
+	for (i = 0; i < 7; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return (u8)i;
+}
+
+/*
+ * For each registered chip, we need to keep some data in memory.
+ * The structure is dynamically allocated.
+ */
+struct w83627hf_data {
+	unsigned short addr;
+	const char *name;
+	struct device *hwmon_dev;
+	struct mutex lock;
+	enum chips type;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[9];		/* Register value */
+	u8 in_max[9];		/* Register value */
+	u8 in_min[9];		/* Register value */
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	u16 temp[3];		/* Register value */
+	u16 temp_max[3];	/* Register value */
+	u16 temp_max_hyst[3];	/* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 vid;			/* Register encoding, combined */
+	u32 alarms;		/* Register encoding, combined */
+	u32 beep_mask;		/* Register encoding, combined */
+	u8 pwm[3];		/* Register value */
+	u8 pwm_enable[3];	/* 1 = manual
+				 * 2 = thermal cruise (also called SmartFan I)
+				 * 3 = fan speed cruise
+				 */
+	u8 pwm_freq[3];		/* Register value */
+	u16 sens[3];		/* 1 = pentium diode; 2 = 3904 diode;
+				 * 4 = thermistor
+				 */
+	u8 vrm;
+	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
+
+#ifdef CONFIG_PM
+	/* Remember extra register values over suspend/resume */
+	u8 scfg1;
+	u8 scfg2;
+#endif
+};
+
+
+static int w83627hf_probe(struct platform_device *pdev);
+static int w83627hf_remove(struct platform_device *pdev);
+
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
+static void w83627hf_update_fan_div(struct w83627hf_data *data);
+static struct w83627hf_data *w83627hf_update_device(struct device *dev);
+static void w83627hf_init_device(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+static int w83627hf_suspend(struct device *dev)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+
+	mutex_lock(&data->update_lock);
+	data->scfg1 = w83627hf_read_value(data, W83781D_REG_SCFG1);
+	data->scfg2 = w83627hf_read_value(data, W83781D_REG_SCFG2);
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static int w83627hf_resume(struct device *dev)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	int i, num_temps = (data->type == w83697hf) ? 2 : 3;
+
+	/* Restore limits */
+	mutex_lock(&data->update_lock);
+	for (i = 0; i <= 8; i++) {
+		/* skip missing sensors */
+		if (((data->type == w83697hf) && (i == 1)) ||
+		    ((data->type != w83627hf && data->type != w83697hf)
+		    && (i == 5 || i == 6)))
+			continue;
+		w83627hf_write_value(data, W83781D_REG_IN_MAX(i),
+				     data->in_max[i]);
+		w83627hf_write_value(data, W83781D_REG_IN_MIN(i),
+				     data->in_min[i]);
+	}
+	for (i = 0; i <= 2; i++)
+		w83627hf_write_value(data, W83627HF_REG_FAN_MIN(i),
+				     data->fan_min[i]);
+	for (i = 0; i < num_temps; i++) {
+		w83627hf_write_value(data, w83627hf_reg_temp_over[i],
+				     data->temp_max[i]);
+		w83627hf_write_value(data, w83627hf_reg_temp_hyst[i],
+				     data->temp_max_hyst[i]);
+	}
+
+	/* Fixup BIOS bugs */
+	if (data->type == w83627thf || data->type == w83637hf ||
+	    data->type == w83687thf)
+		w83627hf_write_value(data, W83627THF_REG_VRM_OVT_CFG,
+				     data->vrm_ovt);
+	w83627hf_write_value(data, W83781D_REG_SCFG1, data->scfg1);
+	w83627hf_write_value(data, W83781D_REG_SCFG2, data->scfg2);
+
+	/* Force re-reading all values */
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops w83627hf_dev_pm_ops = {
+	.suspend = w83627hf_suspend,
+	.resume = w83627hf_resume,
+};
+
+#define W83627HF_DEV_PM_OPS	(&w83627hf_dev_pm_ops)
+#else
+#define W83627HF_DEV_PM_OPS	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver w83627hf_driver = {
+	.driver = {
+		.name	= DRVNAME,
+		.pm	= W83627HF_DEV_PM_OPS,
+	},
+	.probe		= w83627hf_probe,
+	.remove		= w83627hf_remove,
+};
+
+static ssize_t
+show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
+}
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
+}
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
+}
+static ssize_t
+store_in_min(struct device *dev, struct device_attribute *devattr,
+	     const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val);
+	w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+static ssize_t
+store_in_max(struct device *dev, struct device_attribute *devattr,
+	     const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val);
+	w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#define sysfs_vin_decl(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+			  show_in_input, NULL, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR,	\
+			  show_in_min, store_in_min, offset);	\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR,	\
+			  show_in_max, store_in_max, offset);
+
+sysfs_vin_decl(1);
+sysfs_vin_decl(2);
+sysfs_vin_decl(3);
+sysfs_vin_decl(4);
+sysfs_vin_decl(5);
+sysfs_vin_decl(6);
+sysfs_vin_decl(7);
+sysfs_vin_decl(8);
+
+/* use a different set of functions for in0 */
+static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
+{
+	long in0;
+
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
+
+		/* use VRM9 calculation */
+		in0 = (long)((reg * 488 + 70000 + 50) / 100);
+	else
+		/* use VRM8 (standard) calculation */
+		in0 = (long)IN_FROM_REG(reg);
+
+	return sprintf(buf,"%ld\n", in0);
+}
+
+static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in[0]);
+}
+
+static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in_min[0]);
+}
+
+static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in_max[0]);
+}
+
+static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
+
+		/* use VRM9 calculation */
+		data->in_min[0] =
+			clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
+	else
+		/* use VRM8 (standard) calculation */
+		data->in_min[0] = IN_TO_REG(val);
+
+	w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
+		
+		/* use VRM9 calculation */
+		data->in_max[0] =
+			clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
+	else
+		/* use VRM8 (standard) calculation */
+		data->in_max[0] = IN_TO_REG(val);
+
+	w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
+static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
+	show_regs_in_min0, store_regs_in_min0);
+static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+	show_regs_in_max0, store_regs_in_max0);
+
+static ssize_t
+show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
+				(long)DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
+				(long)DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *devattr,
+	      const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr),
+			     data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#define sysfs_fan_decl(offset)	\
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+			  show_fan_input, NULL, offset - 1);		\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+			  show_fan_min, store_fan_min, offset - 1);
+
+sysfs_fan_decl(1);
+sysfs_fan_decl(2);
+sysfs_fan_decl(3);
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+
+	u16 tmp = data->temp[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
+}
+
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *devattr,
+	      char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+
+	u16 tmp = data->temp_max[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
+}
+
+static ssize_t
+show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+		   char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+
+	u16 tmp = data->temp_max_hyst[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
+}
+
+static ssize_t
+store_temp_max(struct device *dev, struct device_attribute *devattr,
+	       const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	u16 tmp;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = tmp;
+	w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+		    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	u16 tmp;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
+	mutex_lock(&data->update_lock);
+	data->temp_max_hyst[nr] = tmp;
+	w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define sysfs_temp_decl(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+			  show_temp, NULL, offset - 1);			\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR,	 	\
+			  show_temp_max, store_temp_max, offset - 1);	\
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR,	\
+			  show_temp_max_hyst, store_temp_max_hyst, offset - 1);
+
+sysfs_temp_decl(1);
+sysfs_temp_decl(2);
+sysfs_temp_decl(3);
+
+static ssize_t
+show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t
+show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%ld\n", (long) data->vrm);
+}
+static ssize_t
+store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+	data->vrm = val;
+
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+static ssize_t
+show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		      (long)BEEP_MASK_FROM_REG(data->beep_mask));
+}
+
+static ssize_t
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	/* preserve beep enable */
+	data->beep_mask = (data->beep_mask & 0x8000)
+			| BEEP_MASK_TO_REG(val);
+	w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
+			    data->beep_mask & 0xff);
+	w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
+			    ((data->beep_mask) >> 16) & 0xff);
+	w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
+			    (data->beep_mask >> 8) & 0xff);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+		   show_beep_mask, store_beep_mask);
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	u8 reg;
+	unsigned long bit;
+	int err;
+
+	err = kstrtoul(buf, 10, &bit);
+	if (err)
+		return err;
+
+	if (bit & ~1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (bit)
+		data->beep_mask |= (1 << bitnr);
+	else
+		data->beep_mask &= ~(1 << bitnr);
+
+	if (bitnr < 8) {
+		reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1);
+		if (bit)
+			reg |= (1 << bitnr);
+		else
+			reg &= ~(1 << bitnr);
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+	} else if (bitnr < 16) {
+		reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
+		if (bit)
+			reg |= (1 << (bitnr - 8));
+		else
+			reg &= ~(1 << (bitnr - 8));
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+	} else {
+		reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3);
+		if (bit)
+			reg |= (1 << (bitnr - 16));
+		else
+			reg &= ~(1 << (bitnr - 16));
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 13);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 15);
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       (long) DIV_FROM_REG(data->fan_div[nr]));
+}
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *devattr,
+	      const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long min;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	data->fan_div[nr] = DIV_TO_REG(val);
+
+	reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+	       & (nr==0 ? 0xcf : 0x3f))
+	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
+	w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+
+	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
+	       & ~(1 << (5 + nr)))
+	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
+	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
+
+	/* Restore fan_min */
+	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
+			  show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
+			  show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
+			  show_fan_div, store_fan_div, 2);
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *devattr,
+	  const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->type == w83627thf) {
+		/* bits 0-3 are reserved  in 627THF */
+		data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
+		w83627hf_write_value(data,
+				     W836X7HF_REG_PWM(data->type, nr),
+				     data->pwm[nr] |
+				     (w83627hf_read_value(data,
+				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
+	} else {
+		data->pwm[nr] = PWM_TO_REG(val);
+		w83627hf_write_value(data,
+				     W836X7HF_REG_PWM(data->type, nr),
+				     data->pwm[nr]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *devattr,
+	  const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (!val || val > 3)	/* modes 1, 2 and 3 are supported */
+		return -EINVAL;
+	mutex_lock(&data->update_lock);
+	data->pwm_enable[nr] = val;
+	reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]);
+	reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]);
+	reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr];
+	w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+						  store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+						  store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+						  store_pwm_enable, 2);
+
+static ssize_t
+show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	if (data->type == w83627hf)
+		return sprintf(buf, "%ld\n",
+			pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
+	else
+		return sprintf(buf, "%ld\n",
+			pwm_freq_from_reg(data->pwm_freq[nr]));
+}
+
+static ssize_t
+store_pwm_freq(struct device *dev, struct device_attribute *devattr,
+	       const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	static const u8 mask[]={0xF8, 0x8F};
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->type == w83627hf) {
+		data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
+		w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
+				(data->pwm_freq[nr] << (nr*4)) |
+				(w83627hf_read_value(data,
+				W83627HF_REG_PWM_FREQ) & mask[nr]));
+	} else {
+		data->pwm_freq[nr] = pwm_freq_to_reg(val);
+		w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
+				data->pwm_freq[nr]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
+			  show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
+			  show_pwm_freq, store_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
+			  show_pwm_freq, store_pwm_freq, 2);
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *devattr,
+	       char *buf)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->sens[nr]);
+}
+
+static ssize_t
+store_temp_type(struct device *dev, struct device_attribute *devattr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u32 tmp;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	switch (val) {
+	case 1:		/* PII/Celeron diode */
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+		w83627hf_write_value(data, W83781D_REG_SCFG2,
+				    tmp | BIT_SCFG2[nr]);
+		data->sens[nr] = val;
+		break;
+	case 2:		/* 3904 */
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+		w83627hf_write_value(data, W83781D_REG_SCFG2,
+				    tmp & ~BIT_SCFG2[nr]);
+		data->sens[nr] = val;
+		break;
+	case W83781D_DEFAULT_BETA:
+		dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+			 "instead\n", W83781D_DEFAULT_BETA);
+		/* fall through */
+	case 4:		/* thermistor */
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
+				    tmp & ~BIT_SCFG1[nr]);
+		data->sens[nr] = val;
+		break;
+	default:
+		dev_err(dev,
+		       "Invalid sensor type %ld; must be 1, 2, or 4\n",
+		       (long) val);
+		break;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define sysfs_temp_type(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+			  show_temp_type, store_temp_type, offset - 1);
+
+sysfs_temp_type(1);
+sysfs_temp_type(2);
+sysfs_temp_type(3);
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+				struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	static __initconst char *const names[] = {
+		"W83627HF",
+		"W83627THF",
+		"W83697HF",
+		"W83637HF",
+		"W83687THF",
+	};
+
+	sio_data->sioaddr = sioaddr;
+	superio_enter(sio_data);
+	val = force_id ? force_id : superio_inb(sio_data, DEVID);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+	       superio_inb(sio_data, WINB_BASE_REG + 1);
+	*addr = val & WINB_ALIGNMENT;
+	if (*addr == 0) {
+		pr_warn("Base address not set, skipping\n");
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, WINB_ACT_REG);
+	if (!(val & 0x01)) {
+		pr_warn("Enabling HWM logical device\n");
+		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
+	}
+
+	err = 0;
+	pr_info(DRVNAME ": Found %s chip at %#x\n",
+		names[sio_data->type], *addr);
+
+ exit:
+	superio_exit(sio_data);
+	return err;
+}
+
+#define VIN_UNIT_ATTRS(_X_)	\
+	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
+	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
+	&sensor_dev_attr_in##_X_##_max.dev_attr.attr,		\
+	&sensor_dev_attr_in##_X_##_alarm.dev_attr.attr,		\
+	&sensor_dev_attr_in##_X_##_beep.dev_attr.attr
+
+#define FAN_UNIT_ATTRS(_X_)	\
+	&sensor_dev_attr_fan##_X_##_input.dev_attr.attr,	\
+	&sensor_dev_attr_fan##_X_##_min.dev_attr.attr,		\
+	&sensor_dev_attr_fan##_X_##_div.dev_attr.attr,		\
+	&sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr,	\
+	&sensor_dev_attr_fan##_X_##_beep.dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(_X_)	\
+	&sensor_dev_attr_temp##_X_##_input.dev_attr.attr,	\
+	&sensor_dev_attr_temp##_X_##_max.dev_attr.attr,		\
+	&sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr,	\
+	&sensor_dev_attr_temp##_X_##_type.dev_attr.attr,	\
+	&sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr,	\
+	&sensor_dev_attr_temp##_X_##_beep.dev_attr.attr
+
+static struct attribute *w83627hf_attributes[] = {
+	&dev_attr_in0_input.attr,
+	&dev_attr_in0_min.attr,
+	&dev_attr_in0_max.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_beep.dev_attr.attr,
+	VIN_UNIT_ATTRS(2),
+	VIN_UNIT_ATTRS(3),
+	VIN_UNIT_ATTRS(4),
+	VIN_UNIT_ATTRS(7),
+	VIN_UNIT_ATTRS(8),
+
+	FAN_UNIT_ATTRS(1),
+	FAN_UNIT_ATTRS(2),
+
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2),
+
+	&dev_attr_alarms.attr,
+	&sensor_dev_attr_beep_enable.dev_attr.attr,
+	&dev_attr_beep_mask.attr,
+
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&dev_attr_name.attr,
+	NULL
+};
+
+static const struct attribute_group w83627hf_group = {
+	.attrs = w83627hf_attributes,
+};
+
+static struct attribute *w83627hf_attributes_opt[] = {
+	VIN_UNIT_ATTRS(1),
+	VIN_UNIT_ATTRS(5),
+	VIN_UNIT_ATTRS(6),
+
+	FAN_UNIT_ATTRS(3),
+	TEMP_UNIT_ATTRS(3),
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+
+	NULL
+};
+
+static const struct attribute_group w83627hf_group_opt = {
+	.attrs = w83627hf_attributes_opt,
+};
+
+static int w83627hf_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(dev);
+	struct w83627hf_data *data;
+	struct resource *res;
+	int err, i;
+
+	static const char *names[] = {
+		"w83627hf",
+		"w83627thf",
+		"w83697hf",
+		"w83637hf",
+		"w83687thf",
+	};
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(dev, res->start, WINB_REGION_SIZE, DRVNAME)) {
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
+		return -EBUSY;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct w83627hf_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->name = names[sio_data->type];
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	/* Initialize the chip */
+	w83627hf_init_device(pdev);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i <= 2; i++)
+		data->fan_min[i] = w83627hf_read_value(
+					data, W83627HF_REG_FAN_MIN(i));
+	w83627hf_update_fan_div(data);
+
+	/* Register common device attributes */
+	err = sysfs_create_group(&dev->kobj, &w83627hf_group);
+	if (err)
+		return err;
+
+	/* Register chip-specific device attributes */
+	if (data->type == w83627hf || data->type == w83697hf)
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_in5_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in5_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in5_max.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in5_alarm.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in5_beep.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in6_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in6_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in6_max.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in6_alarm.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in6_beep.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm1_freq.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm2_freq.dev_attr)))
+			goto error;
+
+	if (data->type != w83697hf)
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_in1_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_max.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_alarm.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_beep.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_div.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_alarm.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_beep.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_max.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_max_hyst.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_alarm.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_beep.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_type.dev_attr)))
+			goto error;
+
+	if (data->type != w83697hf && data->vid != 0xff) {
+		/* Convert VID to voltage based on VRM */
+		data->vrm = vid_which_vrm();
+
+		if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
+		 || (err = device_create_file(dev, &dev_attr_vrm)))
+			goto error;
+	}
+
+	if (data->type == w83627thf || data->type == w83637hf
+	    || data->type == w83687thf) {
+		err = device_create_file(dev, &sensor_dev_attr_pwm3.dev_attr);
+		if (err)
+			goto error;
+	}
+
+	if (data->type == w83637hf || data->type == w83687thf)
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm1_freq.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm2_freq.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm3_freq.dev_attr)))
+			goto error;
+
+	if (data->type != w83627hf)
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm1_enable.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm2_enable.dev_attr)))
+			goto error;
+
+	if (data->type == w83627thf || data->type == w83637hf
+	    || data->type == w83687thf) {
+		err = device_create_file(dev,
+					 &sensor_dev_attr_pwm3_enable.dev_attr);
+		if (err)
+			goto error;
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error;
+	}
+
+	return 0;
+
+ error:
+	sysfs_remove_group(&dev->kobj, &w83627hf_group);
+	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
+	return err;
+}
+
+static int w83627hf_remove(struct platform_device *pdev)
+{
+	struct w83627hf_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+
+	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
+	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
+
+	return 0;
+}
+
+
+/* Registers 0x50-0x5f are banked */
+static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
+{
+	if ((reg & 0x00f0) == 0x50) {
+		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
+	}
+}
+
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
+{
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
+	}
+}
+
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
+{
+	int res, word_sized;
+
+	mutex_lock(&data->lock);
+	word_sized = (((reg & 0xff00) == 0x100)
+		   || ((reg & 0xff00) == 0x200))
+		  && (((reg & 0x00ff) == 0x50)
+		   || ((reg & 0x00ff) == 0x53)
+		   || ((reg & 0x00ff) == 0x55));
+	w83627hf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
+	res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
+	if (word_sized) {
+		outb_p((reg & 0xff) + 1,
+		       data->addr + W83781D_ADDR_REG_OFFSET);
+		res =
+		    (res << 8) + inb_p(data->addr +
+				       W83781D_DATA_REG_OFFSET);
+	}
+	w83627hf_reset_bank(data, reg);
+	mutex_unlock(&data->lock);
+	return res;
+}
+
+static int w83627thf_read_gpio5(struct platform_device *pdev)
+{
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	int res = 0xff, sel;
+
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_GPIO5);
+
+	/* Make sure these GPIO pins are enabled */
+	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
+		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
+		goto exit;
+	}
+
+	/*
+	 * Make sure the pins are configured for input
+	 * There must be at least five (VRM 9), and possibly 6 (VRM 10)
+	 */
+	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
+	if ((sel & 0x1f) != 0x1f) {
+		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
+			"function\n");
+		goto exit;
+	}
+
+	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
+	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
+
+exit:
+	superio_exit(sio_data);
+	return res;
+}
+
+static int w83687thf_read_vid(struct platform_device *pdev)
+{
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+	int res = 0xff;
+
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_HWM);
+
+	/* Make sure these GPIO pins are enabled */
+	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
+		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
+		goto exit;
+	}
+
+	/* Make sure the pins are configured for input */
+	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
+		dev_dbg(&pdev->dev, "VID configured as output, "
+			"no VID function\n");
+		goto exit;
+	}
+
+	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
+
+exit:
+	superio_exit(sio_data);
+	return res;
+}
+
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
+{
+	int word_sized;
+
+	mutex_lock(&data->lock);
+	word_sized = (((reg & 0xff00) == 0x100)
+		   || ((reg & 0xff00) == 0x200))
+		  && (((reg & 0x00ff) == 0x53)
+		   || ((reg & 0x00ff) == 0x55));
+	w83627hf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
+	if (word_sized) {
+		outb_p(value >> 8,
+		       data->addr + W83781D_DATA_REG_OFFSET);
+		outb_p((reg & 0xff) + 1,
+		       data->addr + W83781D_ADDR_REG_OFFSET);
+	}
+	outb_p(value & 0xff,
+	       data->addr + W83781D_DATA_REG_OFFSET);
+	w83627hf_reset_bank(data, reg);
+	mutex_unlock(&data->lock);
+	return 0;
+}
+
+static void w83627hf_init_device(struct platform_device *pdev)
+{
+	struct w83627hf_data *data = platform_get_drvdata(pdev);
+	int i;
+	enum chips type = data->type;
+	u8 tmp;
+
+	/* Minimize conflicts with other winbond i2c-only clients...  */
+	/* disable i2c subclients... how to disable main i2c client?? */
+	/* force i2c address to relatively uncommon address */
+	if (type == w83627hf) {
+		w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
+		w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
+	}
+
+	/* Read VID only once */
+	if (type == w83627hf || type == w83637hf) {
+		int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+		int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
+		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
+	} else if (type == w83627thf) {
+		data->vid = w83627thf_read_gpio5(pdev);
+	} else if (type == w83687thf) {
+		data->vid = w83687thf_read_vid(pdev);
+	}
+
+	/* Read VRM & OVT Config only once */
+	if (type == w83627thf || type == w83637hf || type == w83687thf) {
+		data->vrm_ovt = 
+			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
+	}
+
+	tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+	for (i = 1; i <= 3; i++) {
+		if (!(tmp & BIT_SCFG1[i - 1])) {
+			data->sens[i - 1] = 4;
+		} else {
+			if (w83627hf_read_value
+			    (data,
+			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
+				data->sens[i - 1] = 1;
+			else
+				data->sens[i - 1] = 2;
+		}
+		if ((type == w83697hf) && (i == 2))
+			break;
+	}
+
+	if(init) {
+		/* Enable temp2 */
+		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
+		if (tmp & 0x01) {
+			dev_warn(&pdev->dev, "Enabling temp2, readings "
+				 "might not make sense\n");
+			w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
+				tmp & 0xfe);
+		}
+
+		/* Enable temp3 */
+		if (type != w83697hf) {
+			tmp = w83627hf_read_value(data,
+				W83627HF_REG_TEMP3_CONFIG);
+			if (tmp & 0x01) {
+				dev_warn(&pdev->dev, "Enabling temp3, "
+					 "readings might not make sense\n");
+				w83627hf_write_value(data,
+					W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
+			}
+		}
+	}
+
+	/* Start monitoring */
+	w83627hf_write_value(data, W83781D_REG_CONFIG,
+			    (w83627hf_read_value(data,
+						W83781D_REG_CONFIG) & 0xf7)
+			    | 0x01);
+
+	/* Enable VBAT monitoring if needed */
+	tmp = w83627hf_read_value(data, W83781D_REG_VBAT);
+	if (!(tmp & 0x01))
+		w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01);
+}
+
+static void w83627hf_update_fan_div(struct w83627hf_data *data)
+{
+	int reg;
+
+	reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+	data->fan_div[0] = (reg >> 4) & 0x03;
+	data->fan_div[1] = (reg >> 6) & 0x03;
+	if (data->type != w83697hf) {
+		data->fan_div[2] = (w83627hf_read_value(data,
+				       W83781D_REG_PIN) >> 6) & 0x03;
+	}
+	reg = w83627hf_read_value(data, W83781D_REG_VBAT);
+	data->fan_div[0] |= (reg >> 3) & 0x04;
+	data->fan_div[1] |= (reg >> 4) & 0x04;
+	if (data->type != w83697hf)
+		data->fan_div[2] |= (reg >> 5) & 0x04;
+}
+
+static struct w83627hf_data *w83627hf_update_device(struct device *dev)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	int i, num_temps = (data->type == w83697hf) ? 2 : 3;
+	int num_pwms = (data->type == w83697hf) ? 2 : 3;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		for (i = 0; i <= 8; i++) {
+			/* skip missing sensors */
+			if (((data->type == w83697hf) && (i == 1)) ||
+			    ((data->type != w83627hf && data->type != w83697hf)
+			    && (i == 5 || i == 6)))
+				continue;
+			data->in[i] =
+			    w83627hf_read_value(data, W83781D_REG_IN(i));
+			data->in_min[i] =
+			    w83627hf_read_value(data,
+					       W83781D_REG_IN_MIN(i));
+			data->in_max[i] =
+			    w83627hf_read_value(data,
+					       W83781D_REG_IN_MAX(i));
+		}
+		for (i = 0; i <= 2; i++) {
+			data->fan[i] =
+			    w83627hf_read_value(data, W83627HF_REG_FAN(i));
+			data->fan_min[i] =
+			    w83627hf_read_value(data,
+					       W83627HF_REG_FAN_MIN(i));
+		}
+		for (i = 0; i <= 2; i++) {
+			u8 tmp = w83627hf_read_value(data,
+				W836X7HF_REG_PWM(data->type, i));
+ 			/* bits 0-3 are reserved  in 627THF */
+ 			if (data->type == w83627thf)
+				tmp &= 0xf0;
+			data->pwm[i] = tmp;
+			if (i == 1 &&
+			    (data->type == w83627hf || data->type == w83697hf))
+				break;
+		}
+		if (data->type == w83627hf) {
+				u8 tmp = w83627hf_read_value(data,
+						W83627HF_REG_PWM_FREQ);
+				data->pwm_freq[0] = tmp & 0x07;
+				data->pwm_freq[1] = (tmp >> 4) & 0x07;
+		} else if (data->type != w83627thf) {
+			for (i = 1; i <= 3; i++) {
+				data->pwm_freq[i - 1] =
+					w83627hf_read_value(data,
+						W83637HF_REG_PWM_FREQ[i - 1]);
+				if (i == 2 && (data->type == w83697hf))
+					break;
+			}
+		}
+		if (data->type != w83627hf) {
+			for (i = 0; i < num_pwms; i++) {
+				u8 tmp = w83627hf_read_value(data,
+					W83627THF_REG_PWM_ENABLE[i]);
+				data->pwm_enable[i] =
+					((tmp >> W83627THF_PWM_ENABLE_SHIFT[i])
+					& 0x03) + 1;
+			}
+		}
+		for (i = 0; i < num_temps; i++) {
+			data->temp[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp[i]);
+			data->temp_max[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp_over[i]);
+			data->temp_max_hyst[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp_hyst[i]);
+		}
+
+		w83627hf_update_fan_div(data);
+
+		data->alarms =
+		    w83627hf_read_value(data, W83781D_REG_ALARM1) |
+		    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
+		    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
+		i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
+		data->beep_mask = (i << 8) |
+		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
+		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int __init w83627hf_device_add(unsigned short address,
+				      const struct w83627hf_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address + WINB_REGION_OFFSET,
+		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		pr_err("Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init sensors_w83627hf_init(void)
+{
+	int err;
+	unsigned short address;
+	struct w83627hf_sio_data sio_data;
+
+	if (w83627hf_find(0x2e, &address, &sio_data)
+	 && w83627hf_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	err = platform_driver_register(&w83627hf_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = w83627hf_device_add(address, &sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&w83627hf_driver);
+exit:
+	return err;
+}
+
+static void __exit sensors_w83627hf_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&w83627hf_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	      "Philip Edelbrock <phil@netroedge.com>, "
+	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("W83627HF driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83627hf_init);
+module_exit(sensors_w83627hf_exit);
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
new file mode 100644
index 0000000..54848fd
--- /dev/null
+++ b/drivers/hwmon/w83781d.c
@@ -0,0 +1,2104 @@
+/*
+ * w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>,
+ *			      Philip Edelbrock <phil@netroedge.com>,
+ *			      and Mark Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (c) 2007 - 2008  Jean Delvare <jdelvare@suse.de>
+ *
+ * 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.
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * as99127f	7	3	0	3	0x31	0x12c3	yes	no
+ * as99127f rev.2 (type_name = as99127f)	0x31	0x5ca3	yes	no
+ * w83781d	7	3	0	3	0x10-1	0x5ca3	yes	yes
+ * w83782d	9	3	2-4	3	0x30	0x5ca3	yes	yes
+ * w83783s	5-6	3	2	1-2	0x40	0x5ca3	yes	no
+ *
+ */
+
+#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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_ISA
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#endif
+
+#include "lm75.h"
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+						0x2e, 0x2f, I2C_CLIENT_END };
+
+enum chips { w83781d, w83782d, w83783s, as99127f };
+
+/* Insmod parameters */
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients,
+		 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static bool reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
+
+static bool init = 1;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+
+/* Constants specified below */
+
+/* Length of ISA address segment */
+#define W83781D_EXTENT			8
+
+/* Where are the ISA address/data registers relative to the base address */
+#define W83781D_ADDR_REG_OFFSET		5
+#define W83781D_DATA_REG_OFFSET		6
+
+/* The device registers */
+/* in nr from 0 to 8 */
+#define W83781D_REG_IN_MAX(nr)		((nr < 7) ? (0x2b + (nr) * 2) : \
+						    (0x554 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN_MIN(nr)		((nr < 7) ? (0x2c + (nr) * 2) : \
+						    (0x555 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
+						    (0x550 + (nr) - 7))
+
+/* fan nr from 0 to 2 */
+#define W83781D_REG_FAN_MIN(nr)		(0x3b + (nr))
+#define W83781D_REG_FAN(nr)		(0x28 + (nr))
+
+#define W83781D_REG_BANK		0x4E
+#define W83781D_REG_TEMP2_CONFIG	0x152
+#define W83781D_REG_TEMP3_CONFIG	0x252
+/* temp nr from 1 to 3 */
+#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
+					((nr == 2) ? (0x0150) : \
+						     (0x27)))
+#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
+					((nr == 2) ? (0x153) : \
+						     (0x3A)))
+#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
+					((nr == 2) ? (0x155) : \
+						     (0x39)))
+
+#define W83781D_REG_CONFIG		0x40
+
+/* Interrupt status (W83781D, AS99127F) */
+#define W83781D_REG_ALARM1		0x41
+#define W83781D_REG_ALARM2		0x42
+
+/* Real-time status (W83782D, W83783S) */
+#define W83782D_REG_ALARM1		0x459
+#define W83782D_REG_ALARM2		0x45A
+#define W83782D_REG_ALARM3		0x45B
+
+#define W83781D_REG_BEEP_CONFIG		0x4D
+#define W83781D_REG_BEEP_INTS1		0x56
+#define W83781D_REG_BEEP_INTS2		0x57
+#define W83781D_REG_BEEP_INTS3		0x453	/* not on W83781D */
+
+#define W83781D_REG_VID_FANDIV		0x47
+
+#define W83781D_REG_CHIPID		0x49
+#define W83781D_REG_WCHIPID		0x58
+#define W83781D_REG_CHIPMAN		0x4F
+#define W83781D_REG_PIN			0x4B
+
+/* 782D/783S only */
+#define W83781D_REG_VBAT		0x5D
+
+/* PWM 782D (1-4) and 783S (1-2) only */
+static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
+#define W83781D_REG_PWMCLK12		0x5C
+#define W83781D_REG_PWMCLK34		0x45C
+
+#define W83781D_REG_I2C_ADDR		0x48
+#define W83781D_REG_I2C_SUBADDR		0x4A
+
+/*
+ * The following are undocumented in the data sheets however we
+ * received the information in an email from Winbond tech support
+ */
+/* Sensor selection - not on 781d */
+#define W83781D_REG_SCFG1		0x5D
+static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
+
+#define W83781D_REG_SCFG2		0x59
+static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
+
+#define W83781D_DEFAULT_BETA		3435
+
+/* Conversions */
+#define IN_TO_REG(val)			clamp_val(((val) + 8) / 16, 0, 255)
+#define IN_FROM_REG(val)		((val) * 16)
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static inline long
+FAN_FROM_REG(u8 val, int div)
+{
+	if (val == 0)
+		return -1;
+	if (val == 255)
+		return 0;
+	return 1350000 / (val * div);
+}
+
+#define TEMP_TO_REG(val)		clamp_val((val) / 1000, -127, 128)
+#define TEMP_FROM_REG(val)		((val) * 1000)
+
+#define BEEP_MASK_FROM_REG(val, type)	((type) == as99127f ? \
+					 (~(val)) & 0x7fff : (val) & 0xff7fff)
+#define BEEP_MASK_TO_REG(val, type)	((type) == as99127f ? \
+					 (~(val)) & 0x7fff : (val) & 0xff7fff)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+
+static inline u8
+DIV_TO_REG(long val, enum chips type)
+{
+	int i;
+	val = clamp_val(val, 1,
+			((type == w83781d || type == as99127f) ? 8 : 128)) >> 1;
+	for (i = 0; i < 7; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return i;
+}
+
+struct w83781d_data {
+	struct i2c_client *client;
+	struct device *hwmon_dev;
+	struct mutex lock;
+	enum chips type;
+
+	/* For ISA device only */
+	const char *name;
+	int isa_addr;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	struct i2c_client *lm75[2];	/* for secondary I2C addresses */
+	/* array of 2 pointers to subclients */
+
+	u8 in[9];		/* Register value - 8 & 9 for 782D only */
+	u8 in_max[9];		/* Register value - 8 & 9 for 782D only */
+	u8 in_min[9];		/* Register value - 8 & 9 for 782D only */
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_max;		/* Register value */
+	s8 temp_max_hyst;	/* Register value */
+	u16 temp_add[2];	/* Register value */
+	u16 temp_max_add[2];	/* Register value */
+	u16 temp_max_hyst_add[2];	/* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 vid;			/* Register encoding, combined */
+	u32 alarms;		/* Register encoding, combined */
+	u32 beep_mask;		/* Register encoding, combined */
+	u8 pwm[4];		/* Register value */
+	u8 pwm2_enable;		/* Boolean */
+	u16 sens[3];		/*
+				 * 782D/783S only.
+				 * 1 = pentium diode; 2 = 3904 diode;
+				 * 4 = thermistor
+				 */
+	u8 vrm;
+};
+
+static struct w83781d_data *w83781d_data_if_isa(void);
+static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
+
+static int w83781d_read_value(struct w83781d_data *data, u16 reg);
+static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
+static struct w83781d_data *w83781d_update_device(struct device *dev);
+static void w83781d_init_device(struct device *dev);
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
+		char *buf) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = w83781d_update_device(dev); \
+	return sprintf(buf, "%ld\n", \
+		       (long)IN_FROM_REG(data->reg[attr->index])); \
+}
+show_in_reg(in);
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg(struct device *dev, struct device_attribute \
+		*da, const char *buf, size_t count) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = dev_get_drvdata(dev); \
+	int nr = attr->index; \
+	unsigned long val; \
+	int err = kstrtoul(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = IN_TO_REG(val); \
+	w83781d_write_value(data, W83781D_REG_IN_##REG(nr), \
+			    data->in_##reg[nr]); \
+	\
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+#define sysfs_in_offsets(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+		show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+		show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+		show_in_max, store_in_max, offset)
+
+sysfs_in_offsets(0);
+sysfs_in_offsets(1);
+sysfs_in_offsets(2);
+sysfs_in_offsets(3);
+sysfs_in_offsets(4);
+sysfs_in_offsets(5);
+sysfs_in_offsets(6);
+sysfs_in_offsets(7);
+sysfs_in_offsets(8);
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
+		char *buf) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = w83781d_update_device(dev); \
+	return sprintf(buf, "%ld\n", \
+		FAN_FROM_REG(data->reg[attr->index], \
+			DIV_FROM_REG(data->fan_div[attr->index]))); \
+}
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] =
+	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
+			    data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+		show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+		show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+		show_fan_min, store_fan_min, 2);
+
+#define show_temp_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
+		char *buf) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = w83781d_update_device(dev); \
+	int nr = attr->index; \
+	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
+		return sprintf(buf, "%d\n", \
+			LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
+	} else {	/* TEMP1 */ \
+		return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->reg)); \
+	} \
+}
+show_temp_reg(temp);
+show_temp_reg(temp_max);
+show_temp_reg(temp_max_hyst);
+
+#define store_temp_reg(REG, reg) \
+static ssize_t store_temp_##reg(struct device *dev, \
+		struct device_attribute *da, const char *buf, size_t count) \
+{ \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = dev_get_drvdata(dev); \
+	int nr = attr->index; \
+	long val; \
+	int err = kstrtol(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	 \
+	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
+		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
+		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
+				data->temp_##reg##_add[nr-2]); \
+	} else {	/* TEMP1 */ \
+		data->temp_##reg = TEMP_TO_REG(val); \
+		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
+			data->temp_##reg); \
+	} \
+	 \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+store_temp_reg(OVER, max);
+store_temp_reg(HYST, max_hyst);
+
+#define sysfs_temp_offsets(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+		show_temp, NULL, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+		show_temp_max, store_temp_max, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
+		show_temp_max_hyst, store_temp_max_hyst, offset);
+
+sysfs_temp_offsets(1);
+sysfs_temp_offsets(2);
+sysfs_temp_offsets(3);
+
+static ssize_t
+show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t
+show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%ld\n", (long) data->vrm);
+}
+
+static ssize_t
+store_vrm_reg(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	data->vrm = clamp_val(val, 0, 255);
+
+	return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+/* The W83781D has a single alarm bit for temp2 and temp3 */
+static ssize_t show_temp3_alarm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	int bitnr = (data->type == w83781d) ? 5 : 13;
+	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
+
+static ssize_t show_beep_mask(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
+}
+
+static ssize_t
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->beep_mask &= 0x8000; /* preserve beep enable */
+	data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
+	w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
+			    data->beep_mask & 0xff);
+	w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
+			    (data->beep_mask >> 8) & 0xff);
+	if (data->type != w83781d && data->type != as99127f) {
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
+				    ((data->beep_mask) >> 16) & 0xff);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+		show_beep_mask, store_beep_mask);
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int bitnr = to_sensor_dev_attr(attr)->index;
+	u8 reg;
+	unsigned long bit;
+	int err;
+
+	err = kstrtoul(buf, 10, &bit);
+	if (err)
+		return err;
+
+	if (bit & ~1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (bit)
+		data->beep_mask |= (1 << bitnr);
+	else
+		data->beep_mask &= ~(1 << bitnr);
+
+	if (bitnr < 8) {
+		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
+		if (bit)
+			reg |= (1 << bitnr);
+		else
+			reg &= ~(1 << bitnr);
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+	} else if (bitnr < 16) {
+		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
+		if (bit)
+			reg |= (1 << (bitnr - 8));
+		else
+			reg &= ~(1 << (bitnr - 8));
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+	} else {
+		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
+		if (bit)
+			reg |= (1 << (bitnr - 16));
+		else
+			reg &= ~(1 << (bitnr - 16));
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* The W83781D has a single beep bit for temp2 and temp3 */
+static ssize_t show_temp3_beep(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	int bitnr = (data->type == w83781d) ? 5 : 13;
+	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
+			show_temp3_beep, store_beep, 13);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+			show_beep, store_beep, 15);
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       (long) DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	unsigned long min;
+	int nr = attr->index;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	data->fan_div[nr] = DIV_TO_REG(val, data->type);
+
+	reg = (w83781d_read_value(data, nr == 2 ?
+				  W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+		& (nr == 0 ? 0xcf : 0x3f))
+	      | ((data->fan_div[nr] & 0x03) << (nr == 0 ? 4 : 6));
+	w83781d_write_value(data, nr == 2 ?
+			    W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+
+	/* w83781d and as99127f don't have extended divisor bits */
+	if (data->type != w83781d && data->type != as99127f) {
+		reg = (w83781d_read_value(data, W83781D_REG_VBAT)
+		       & ~(1 << (5 + nr)))
+		    | ((data->fan_div[nr] & 0x04) << (3 + nr));
+		w83781d_write_value(data, W83781D_REG_VBAT, reg);
+	}
+
+	/* Restore fan_min */
+	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 2);
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
+}
+
+static ssize_t
+show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%d\n", (int)data->pwm2_enable);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
+		size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = clamp_val(val, 0, 255);
+	w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_pwm2_enable(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	u32 reg;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	switch (val) {
+	case 0:
+	case 1:
+		reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
+		w83781d_write_value(data, W83781D_REG_PWMCLK12,
+				    (reg & 0xf7) | (val << 3));
+
+		reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
+				    (reg & 0xef) | (!val << 4));
+
+		data->pwm2_enable = val;
+		break;
+
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
+/* only PWM2 can be enabled/disabled */
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+		show_pwm2_enable, store_pwm2_enable);
+
+static ssize_t
+show_sensor(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
+}
+
+static ssize_t
+store_sensor(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	unsigned long val;
+	u32 tmp;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	switch (val) {
+	case 1:		/* PII/Celeron diode */
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+		w83781d_write_value(data, W83781D_REG_SCFG2,
+				    tmp | BIT_SCFG2[nr]);
+		data->sens[nr] = val;
+		break;
+	case 2:		/* 3904 */
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+		w83781d_write_value(data, W83781D_REG_SCFG2,
+				    tmp & ~BIT_SCFG2[nr]);
+		data->sens[nr] = val;
+		break;
+	case W83781D_DEFAULT_BETA:
+		dev_warn(dev,
+			 "Sensor type %d is deprecated, please use 4 instead\n",
+			 W83781D_DEFAULT_BETA);
+		/* fall through */
+	case 4:		/* thermistor */
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp & ~BIT_SCFG1[nr]);
+		data->sens[nr] = val;
+		break;
+	default:
+		dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
+		       (long) val);
+		break;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 1);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 2);
+
+/*
+ * Assumes that adapter is of I2C, not ISA variety.
+ * OTHERWISE DON'T CALL THIS
+ */
+static int
+w83781d_detect_subclients(struct i2c_client *new_client)
+{
+	int i, val1 = 0, id;
+	int err;
+	int address = new_client->addr;
+	unsigned short sc_addr[2];
+	struct i2c_adapter *adapter = new_client->adapter;
+	struct w83781d_data *data = i2c_get_clientdata(new_client);
+	enum chips kind = data->type;
+	int num_sc = 1;
+
+	id = i2c_adapter_id(adapter);
+
+	if (force_subclients[0] == id && force_subclients[1] == address) {
+		for (i = 2; i <= 3; i++) {
+			if (force_subclients[i] < 0x48 ||
+			    force_subclients[i] > 0x4f) {
+				dev_err(&new_client->dev,
+					"Invalid subclient address %d; must be 0x48-0x4f\n",
+					force_subclients[i]);
+				err = -EINVAL;
+				goto ERROR_SC_1;
+			}
+		}
+		w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
+				(force_subclients[2] & 0x07) |
+				((force_subclients[3] & 0x07) << 4));
+		sc_addr[0] = force_subclients[2];
+	} else {
+		val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
+		sc_addr[0] = 0x48 + (val1 & 0x07);
+	}
+
+	if (kind != w83783s) {
+		num_sc = 2;
+		if (force_subclients[0] == id &&
+		    force_subclients[1] == address) {
+			sc_addr[1] = force_subclients[3];
+		} else {
+			sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
+		}
+		if (sc_addr[0] == sc_addr[1]) {
+			dev_err(&new_client->dev,
+			       "Duplicate addresses 0x%x for subclients.\n",
+			       sc_addr[0]);
+			err = -EBUSY;
+			goto ERROR_SC_2;
+		}
+	}
+
+	for (i = 0; i < num_sc; i++) {
+		data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
+		if (!data->lm75[i]) {
+			dev_err(&new_client->dev,
+				"Subclient %d registration at address 0x%x failed.\n",
+				i, sc_addr[i]);
+			err = -ENOMEM;
+			if (i == 1)
+				goto ERROR_SC_3;
+			goto ERROR_SC_2;
+		}
+	}
+
+	return 0;
+
+/* Undo inits in case of errors */
+ERROR_SC_3:
+	i2c_unregister_device(data->lm75[0]);
+ERROR_SC_2:
+ERROR_SC_1:
+	return err;
+}
+
+#define IN_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_in##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_min.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_max.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_alarm.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_beep.dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_fan##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_min.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_div.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_alarm.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_beep.dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_temp##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_temp##X##_max.dev_attr.attr,		\
+	&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr,	\
+	&sensor_dev_attr_temp##X##_alarm.dev_attr.attr,		\
+	&sensor_dev_attr_temp##X##_beep.dev_attr.attr
+
+static struct attribute *w83781d_attributes[] = {
+	IN_UNIT_ATTRS(0),
+	IN_UNIT_ATTRS(2),
+	IN_UNIT_ATTRS(3),
+	IN_UNIT_ATTRS(4),
+	IN_UNIT_ATTRS(5),
+	IN_UNIT_ATTRS(6),
+	FAN_UNIT_ATTRS(1),
+	FAN_UNIT_ATTRS(2),
+	FAN_UNIT_ATTRS(3),
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2),
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_beep_mask.attr,
+	&sensor_dev_attr_beep_enable.dev_attr.attr,
+	NULL
+};
+static const struct attribute_group w83781d_group = {
+	.attrs = w83781d_attributes,
+};
+
+static struct attribute *w83781d_attributes_in1[] = {
+	IN_UNIT_ATTRS(1),
+	NULL
+};
+static const struct attribute_group w83781d_group_in1 = {
+	.attrs = w83781d_attributes_in1,
+};
+
+static struct attribute *w83781d_attributes_in78[] = {
+	IN_UNIT_ATTRS(7),
+	IN_UNIT_ATTRS(8),
+	NULL
+};
+static const struct attribute_group w83781d_group_in78 = {
+	.attrs = w83781d_attributes_in78,
+};
+
+static struct attribute *w83781d_attributes_temp3[] = {
+	TEMP_UNIT_ATTRS(3),
+	NULL
+};
+static const struct attribute_group w83781d_group_temp3 = {
+	.attrs = w83781d_attributes_temp3,
+};
+
+static struct attribute *w83781d_attributes_pwm12[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&dev_attr_pwm2_enable.attr,
+	NULL
+};
+static const struct attribute_group w83781d_group_pwm12 = {
+	.attrs = w83781d_attributes_pwm12,
+};
+
+static struct attribute *w83781d_attributes_pwm34[] = {
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.attr,
+	NULL
+};
+static const struct attribute_group w83781d_group_pwm34 = {
+	.attrs = w83781d_attributes_pwm34,
+};
+
+static struct attribute *w83781d_attributes_other[] = {
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
+	NULL
+};
+static const struct attribute_group w83781d_group_other = {
+	.attrs = w83781d_attributes_other,
+};
+
+/* No clean up is done on error, it's up to the caller */
+static int
+w83781d_create_files(struct device *dev, int kind, int is_isa)
+{
+	int err;
+
+	err = sysfs_create_group(&dev->kobj, &w83781d_group);
+	if (err)
+		return err;
+
+	if (kind != w83783s) {
+		err = sysfs_create_group(&dev->kobj, &w83781d_group_in1);
+		if (err)
+			return err;
+	}
+	if (kind != as99127f && kind != w83781d && kind != w83783s) {
+		err = sysfs_create_group(&dev->kobj, &w83781d_group_in78);
+		if (err)
+			return err;
+	}
+	if (kind != w83783s) {
+		err = sysfs_create_group(&dev->kobj, &w83781d_group_temp3);
+		if (err)
+			return err;
+
+		if (kind != w83781d) {
+			err = sysfs_chmod_file(&dev->kobj,
+				&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+				S_IRUGO | S_IWUSR);
+			if (err)
+				return err;
+		}
+	}
+
+	if (kind != w83781d && kind != as99127f) {
+		err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm12);
+		if (err)
+			return err;
+	}
+	if (kind == w83782d && !is_isa) {
+		err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm34);
+		if (err)
+			return err;
+	}
+
+	if (kind != as99127f && kind != w83781d) {
+		err = device_create_file(dev,
+					 &sensor_dev_attr_temp1_type.dev_attr);
+		if (err)
+			return err;
+		err = device_create_file(dev,
+					 &sensor_dev_attr_temp2_type.dev_attr);
+		if (err)
+			return err;
+		if (kind != w83783s) {
+			err = device_create_file(dev,
+					&sensor_dev_attr_temp3_type.dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int
+w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	int val1, val2;
+	struct w83781d_data *isa = w83781d_data_if_isa();
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	const char *client_name;
+	enum vendor { winbond, asus } vendid;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/*
+	 * We block updates of the ISA device to minimize the risk of
+	 * concurrent access to the same W83781D chip through different
+	 * interfaces.
+	 */
+	if (isa)
+		mutex_lock(&isa->update_lock);
+
+	if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
+		dev_dbg(&adapter->dev,
+			"Detection of w83781d chip failed at step 3\n");
+		goto err_nodev;
+	}
+
+	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
+	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
+	/* Check for Winbond or Asus ID if in bank 0 */
+	if (!(val1 & 0x07) &&
+	    ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
+	     ((val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
+		dev_dbg(&adapter->dev,
+			"Detection of w83781d chip failed at step 4\n");
+		goto err_nodev;
+	}
+	/*
+	 * If Winbond SMBus, check address at 0x48.
+	 * Asus doesn't support, except for as99127f rev.2
+	 */
+	if ((!(val1 & 0x80) && val2 == 0xa3) ||
+	    ((val1 & 0x80) && val2 == 0x5c)) {
+		if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
+		    != address) {
+			dev_dbg(&adapter->dev,
+				"Detection of w83781d chip failed at step 5\n");
+			goto err_nodev;
+		}
+	}
+
+	/* Put it now into bank 0 and Vendor ID High Byte */
+	i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
+		(i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
+		 & 0x78) | 0x80);
+
+	/* Get the vendor ID */
+	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
+	if (val2 == 0x5c)
+		vendid = winbond;
+	else if (val2 == 0x12)
+		vendid = asus;
+	else {
+		dev_dbg(&adapter->dev,
+			"w83781d chip vendor is neither Winbond nor Asus\n");
+		goto err_nodev;
+	}
+
+	/* Determine the chip type. */
+	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
+	if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
+		client_name = "w83781d";
+	else if (val1 == 0x30 && vendid == winbond)
+		client_name = "w83782d";
+	else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
+		client_name = "w83783s";
+	else if (val1 == 0x31)
+		client_name = "as99127f";
+	else
+		goto err_nodev;
+
+	if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
+		dev_dbg(&adapter->dev,
+			"Device at 0x%02x appears to be the same as ISA device\n",
+			address);
+		goto err_nodev;
+	}
+
+	if (isa)
+		mutex_unlock(&isa->update_lock);
+
+	strlcpy(info->type, client_name, I2C_NAME_SIZE);
+
+	return 0;
+
+ err_nodev:
+	if (isa)
+		mutex_unlock(&isa->update_lock);
+	return -ENODEV;
+}
+
+static void w83781d_remove_files(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &w83781d_group);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_in1);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_in78);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_temp3);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_pwm12);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_pwm34);
+	sysfs_remove_group(&dev->kobj, &w83781d_group_other);
+}
+
+static int
+w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct w83781d_data *data;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct w83781d_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->lock);
+	mutex_init(&data->update_lock);
+
+	data->type = id->driver_data;
+	data->client = client;
+
+	/* attach secondary i2c lm75-like clients */
+	err = w83781d_detect_subclients(client);
+	if (err)
+		return err;
+
+	/* Initialize the chip */
+	w83781d_init_device(dev);
+
+	/* Register sysfs hooks */
+	err = w83781d_create_files(dev, data->type, 0);
+	if (err)
+		goto exit_remove_files;
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+
+	return 0;
+
+ exit_remove_files:
+	w83781d_remove_files(dev);
+	if (data->lm75[0])
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1])
+		i2c_unregister_device(data->lm75[1]);
+	return err;
+}
+
+static int
+w83781d_remove(struct i2c_client *client)
+{
+	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+
+	hwmon_device_unregister(data->hwmon_dev);
+	w83781d_remove_files(dev);
+
+	if (data->lm75[0])
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1])
+		i2c_unregister_device(data->lm75[1]);
+
+	return 0;
+}
+
+static int
+w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
+{
+	struct i2c_client *client = data->client;
+	int res, bank;
+	struct i2c_client *cl;
+
+	bank = (reg >> 8) & 0x0f;
+	if (bank > 2)
+		/* switch banks */
+		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
+					  bank);
+	if (bank == 0 || bank > 2) {
+		res = i2c_smbus_read_byte_data(client, reg & 0xff);
+	} else {
+		/* switch to subclient */
+		cl = data->lm75[bank - 1];
+		/* convert from ISA to LM75 I2C addresses */
+		switch (reg & 0xff) {
+		case 0x50:	/* TEMP */
+			res = i2c_smbus_read_word_swapped(cl, 0);
+			break;
+		case 0x52:	/* CONFIG */
+			res = i2c_smbus_read_byte_data(cl, 1);
+			break;
+		case 0x53:	/* HYST */
+			res = i2c_smbus_read_word_swapped(cl, 2);
+			break;
+		case 0x55:	/* OVER */
+		default:
+			res = i2c_smbus_read_word_swapped(cl, 3);
+			break;
+		}
+	}
+	if (bank > 2)
+		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
+
+	return res;
+}
+
+static int
+w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
+{
+	struct i2c_client *client = data->client;
+	int bank;
+	struct i2c_client *cl;
+
+	bank = (reg >> 8) & 0x0f;
+	if (bank > 2)
+		/* switch banks */
+		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
+					  bank);
+	if (bank == 0 || bank > 2) {
+		i2c_smbus_write_byte_data(client, reg & 0xff,
+					  value & 0xff);
+	} else {
+		/* switch to subclient */
+		cl = data->lm75[bank - 1];
+		/* convert from ISA to LM75 I2C addresses */
+		switch (reg & 0xff) {
+		case 0x52:	/* CONFIG */
+			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
+			break;
+		case 0x53:	/* HYST */
+			i2c_smbus_write_word_swapped(cl, 2, value);
+			break;
+		case 0x55:	/* OVER */
+			i2c_smbus_write_word_swapped(cl, 3, value);
+			break;
+		}
+	}
+	if (bank > 2)
+		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
+
+	return 0;
+}
+
+static void
+w83781d_init_device(struct device *dev)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int i, p;
+	int type = data->type;
+	u8 tmp;
+
+	if (reset && type != as99127f) { /*
+					  * this resets registers we don't have
+					  * documentation for on the as99127f
+					  */
+		/*
+		 * Resetting the chip has been the default for a long time,
+		 * but it causes the BIOS initializations (fan clock dividers,
+		 * thermal sensor types...) to be lost, so it is now optional.
+		 * It might even go away if nobody reports it as being useful,
+		 * as I see very little reason why this would be needed at
+		 * all.
+		 */
+		dev_info(dev,
+			 "If reset=1 solved a problem you were having, please report!\n");
+
+		/* save these registers */
+		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
+		/*
+		 * Reset all except Watchdog values and last conversion values
+		 * This sets fan-divs to 2, among others
+		 */
+		w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
+		/*
+		 * Restore the registers and disable power-on abnormal beep.
+		 * This saves FAN 1/2/3 input/output values set by BIOS.
+		 */
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
+		w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
+		/*
+		 * Disable master beep-enable (reset turns it on).
+		 * Individual beep_mask should be reset to off but for some
+		 * reason disabling this bit helps some people not get beeped
+		 */
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
+	}
+
+	/*
+	 * Disable power-on abnormal beep, as advised by the datasheet.
+	 * Already done if reset=1.
+	 */
+	if (init && !reset && type != as99127f) {
+		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
+	}
+
+	data->vrm = vid_which_vrm();
+
+	if ((type != w83781d) && (type != as99127f)) {
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		for (i = 1; i <= 3; i++) {
+			if (!(tmp & BIT_SCFG1[i - 1])) {
+				data->sens[i - 1] = 4;
+			} else {
+				if (w83781d_read_value
+				    (data,
+				     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
+					data->sens[i - 1] = 1;
+				else
+					data->sens[i - 1] = 2;
+			}
+			if (type == w83783s && i == 2)
+				break;
+		}
+	}
+
+	if (init && type != as99127f) {
+		/* Enable temp2 */
+		tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
+		if (tmp & 0x01) {
+			dev_warn(dev,
+				 "Enabling temp2, readings might not make sense\n");
+			w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
+				tmp & 0xfe);
+		}
+
+		/* Enable temp3 */
+		if (type != w83783s) {
+			tmp = w83781d_read_value(data,
+				W83781D_REG_TEMP3_CONFIG);
+			if (tmp & 0x01) {
+				dev_warn(dev,
+					 "Enabling temp3, readings might not make sense\n");
+				w83781d_write_value(data,
+					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+			}
+		}
+	}
+
+	/* Start monitoring */
+	w83781d_write_value(data, W83781D_REG_CONFIG,
+			    (w83781d_read_value(data,
+						W83781D_REG_CONFIG) & 0xf7)
+			    | 0x01);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 3; i++) {
+		data->fan_min[i] = w83781d_read_value(data,
+					W83781D_REG_FAN_MIN(i));
+	}
+
+	mutex_init(&data->update_lock);
+}
+
+static struct w83781d_data *w83781d_update_device(struct device *dev)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		dev_dbg(dev, "Starting device update\n");
+
+		for (i = 0; i <= 8; i++) {
+			if (data->type == w83783s && i == 1)
+				continue;	/* 783S has no in1 */
+			data->in[i] =
+			    w83781d_read_value(data, W83781D_REG_IN(i));
+			data->in_min[i] =
+			    w83781d_read_value(data, W83781D_REG_IN_MIN(i));
+			data->in_max[i] =
+			    w83781d_read_value(data, W83781D_REG_IN_MAX(i));
+			if ((data->type != w83782d) && (i == 6))
+				break;
+		}
+		for (i = 0; i < 3; i++) {
+			data->fan[i] =
+			    w83781d_read_value(data, W83781D_REG_FAN(i));
+			data->fan_min[i] =
+			    w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
+		}
+		if (data->type != w83781d && data->type != as99127f) {
+			for (i = 0; i < 4; i++) {
+				data->pwm[i] =
+				    w83781d_read_value(data,
+						       W83781D_REG_PWM[i]);
+				/* Only W83782D on SMBus has PWM3 and PWM4 */
+				if ((data->type != w83782d || !client)
+				    && i == 1)
+					break;
+			}
+			/* Only PWM2 can be disabled */
+			data->pwm2_enable = (w83781d_read_value(data,
+					     W83781D_REG_PWMCLK12) & 0x08) >> 3;
+		}
+
+		data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
+		data->temp_max =
+		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
+		data->temp_max_hyst =
+		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
+		data->temp_add[0] =
+		    w83781d_read_value(data, W83781D_REG_TEMP(2));
+		data->temp_max_add[0] =
+		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
+		data->temp_max_hyst_add[0] =
+		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
+		if (data->type != w83783s) {
+			data->temp_add[1] =
+			    w83781d_read_value(data, W83781D_REG_TEMP(3));
+			data->temp_max_add[1] =
+			    w83781d_read_value(data,
+					       W83781D_REG_TEMP_OVER(3));
+			data->temp_max_hyst_add[1] =
+			    w83781d_read_value(data,
+					       W83781D_REG_TEMP_HYST(3));
+		}
+		i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
+		data->vid = i & 0x0f;
+		data->vid |= (w83781d_read_value(data,
+					W83781D_REG_CHIPID) & 0x01) << 4;
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = (i >> 6) & 0x03;
+		data->fan_div[2] = (w83781d_read_value(data,
+					W83781D_REG_PIN) >> 6) & 0x03;
+		if ((data->type != w83781d) && (data->type != as99127f)) {
+			i = w83781d_read_value(data, W83781D_REG_VBAT);
+			data->fan_div[0] |= (i >> 3) & 0x04;
+			data->fan_div[1] |= (i >> 4) & 0x04;
+			data->fan_div[2] |= (i >> 5) & 0x04;
+		}
+		if (data->type == w83782d) {
+			data->alarms = w83781d_read_value(data,
+						W83782D_REG_ALARM1)
+				     | (w83781d_read_value(data,
+						W83782D_REG_ALARM2) << 8)
+				     | (w83781d_read_value(data,
+						W83782D_REG_ALARM3) << 16);
+		} else if (data->type == w83783s) {
+			data->alarms = w83781d_read_value(data,
+						W83782D_REG_ALARM1)
+				     | (w83781d_read_value(data,
+						W83782D_REG_ALARM2) << 8);
+		} else {
+			/*
+			 * No real-time status registers, fall back to
+			 * interrupt status registers
+			 */
+			data->alarms = w83781d_read_value(data,
+						W83781D_REG_ALARM1)
+				     | (w83781d_read_value(data,
+						W83781D_REG_ALARM2) << 8);
+		}
+		i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
+		data->beep_mask = (i << 8) +
+		    w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
+		if ((data->type != w83781d) && (data->type != as99127f)) {
+			data->beep_mask |=
+			    w83781d_read_value(data,
+					       W83781D_REG_BEEP_INTS3) << 16;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static const struct i2c_device_id w83781d_ids[] = {
+	{ "w83781d", w83781d, },
+	{ "w83782d", w83782d, },
+	{ "w83783s", w83783s, },
+	{ "as99127f", as99127f },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, w83781d_ids);
+
+static struct i2c_driver w83781d_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name = "w83781d",
+	},
+	.probe		= w83781d_probe,
+	.remove		= w83781d_remove,
+	.id_table	= w83781d_ids,
+	.detect		= w83781d_detect,
+	.address_list	= normal_i2c,
+};
+
+/*
+ * ISA related code
+ */
+#ifdef CONFIG_ISA
+
+/* ISA device, if found */
+static struct platform_device *pdev;
+
+static unsigned short isa_address = 0x290;
+
+/*
+ * I2C devices get this name attribute automatically, but for ISA devices
+ * we must create it by ourselves.
+ */
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct w83781d_data *w83781d_data_if_isa(void)
+{
+	return pdev ? platform_get_drvdata(pdev) : NULL;
+}
+
+/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
+static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
+{
+	struct w83781d_data *isa;
+	int i;
+
+	if (!pdev)	/* No ISA chip */
+		return 0;
+
+	isa = platform_get_drvdata(pdev);
+
+	if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
+		return 0;	/* Address doesn't match */
+	if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
+		return 0;	/* Chip type doesn't match */
+
+	/*
+	 * We compare all the limit registers, the config register and the
+	 * interrupt mask registers
+	 */
+	for (i = 0x2b; i <= 0x3d; i++) {
+		if (w83781d_read_value(isa, i) !=
+		    i2c_smbus_read_byte_data(client, i))
+			return 0;
+	}
+	if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
+	    i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
+		return 0;
+	for (i = 0x43; i <= 0x46; i++) {
+		if (w83781d_read_value(isa, i) !=
+		    i2c_smbus_read_byte_data(client, i))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int
+w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
+{
+	int word_sized, res;
+
+	word_sized = (((reg & 0xff00) == 0x100)
+		      || ((reg & 0xff00) == 0x200))
+	    && (((reg & 0x00ff) == 0x50)
+		|| ((reg & 0x00ff) == 0x53)
+		|| ((reg & 0x00ff) == 0x55));
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(reg >> 8,
+		       data->isa_addr + W83781D_DATA_REG_OFFSET);
+	}
+	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
+	res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
+	if (word_sized) {
+		outb_p((reg & 0xff) + 1,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+		res =
+		    (res << 8) + inb_p(data->isa_addr +
+				       W83781D_DATA_REG_OFFSET);
+	}
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
+	}
+	return res;
+}
+
+static void
+w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
+{
+	int word_sized;
+
+	word_sized = (((reg & 0xff00) == 0x100)
+		      || ((reg & 0xff00) == 0x200))
+	    && (((reg & 0x00ff) == 0x53)
+		|| ((reg & 0x00ff) == 0x55));
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(reg >> 8,
+		       data->isa_addr + W83781D_DATA_REG_OFFSET);
+	}
+	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
+	if (word_sized) {
+		outb_p(value >> 8,
+		       data->isa_addr + W83781D_DATA_REG_OFFSET);
+		outb_p((reg & 0xff) + 1,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+	}
+	outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
+	}
+}
+
+/*
+ * The SMBus locks itself, usually, but nothing may access the Winbond between
+ * bank switches. ISA access must always be locked explicitly!
+ * We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the W83781D access and should not be necessary.
+ * There are some ugly typecasts here, but the good news is - they should
+ * nowhere else be necessary!
+ */
+static int
+w83781d_read_value(struct w83781d_data *data, u16 reg)
+{
+	struct i2c_client *client = data->client;
+	int res;
+
+	mutex_lock(&data->lock);
+	if (client)
+		res = w83781d_read_value_i2c(data, reg);
+	else
+		res = w83781d_read_value_isa(data, reg);
+	mutex_unlock(&data->lock);
+	return res;
+}
+
+static int
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
+{
+	struct i2c_client *client = data->client;
+
+	mutex_lock(&data->lock);
+	if (client)
+		w83781d_write_value_i2c(data, reg, value);
+	else
+		w83781d_write_value_isa(data, reg, value);
+	mutex_unlock(&data->lock);
+	return 0;
+}
+
+static int
+w83781d_isa_probe(struct platform_device *pdev)
+{
+	int err, reg;
+	struct w83781d_data *data;
+	struct resource *res;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!devm_request_region(&pdev->dev,
+				 res->start + W83781D_ADDR_REG_OFFSET, 2,
+				 "w83781d"))
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct w83781d_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->lock);
+	data->isa_addr = res->start;
+	platform_set_drvdata(pdev, data);
+
+	reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
+	switch (reg) {
+	case 0x30:
+		data->type = w83782d;
+		data->name = "w83782d";
+		break;
+	default:
+		data->type = w83781d;
+		data->name = "w83781d";
+	}
+
+	/* Initialize the W83781D chip */
+	w83781d_init_device(&pdev->dev);
+
+	/* Register sysfs hooks */
+	err = w83781d_create_files(&pdev->dev, data->type, 1);
+	if (err)
+		goto exit_remove_files;
+
+	err = device_create_file(&pdev->dev, &dev_attr_name);
+	if (err)
+		goto exit_remove_files;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+
+	return 0;
+
+ exit_remove_files:
+	w83781d_remove_files(&pdev->dev);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	return err;
+}
+
+static int
+w83781d_isa_remove(struct platform_device *pdev)
+{
+	struct w83781d_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	w83781d_remove_files(&pdev->dev);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+
+	return 0;
+}
+
+static struct platform_driver w83781d_isa_driver = {
+	.driver = {
+		.name = "w83781d",
+	},
+	.probe = w83781d_isa_probe,
+	.remove = w83781d_isa_remove,
+};
+
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init
+w83781d_isa_found(unsigned short address)
+{
+	int val, save, found = 0;
+	int port;
+
+	/*
+	 * Some boards declare base+0 to base+7 as a PNP device, some base+4
+	 * to base+7 and some base+5 to base+6. So we better request each port
+	 * individually for the probing phase.
+	 */
+	for (port = address; port < address + W83781D_EXTENT; port++) {
+		if (!request_region(port, 1, "w83781d")) {
+			pr_debug("Failed to request port 0x%x\n", port);
+			goto release;
+		}
+	}
+
+#define REALLY_SLOW_IO
+	/*
+	 * We need the timeouts for at least some W83781D-like
+	 * chips. But only if we read 'undefined' registers.
+	 */
+	val = inb_p(address + 1);
+	if (inb_p(address + 2) != val
+	 || inb_p(address + 3) != val
+	 || inb_p(address + 7) != val) {
+		pr_debug("Detection failed at step %d\n", 1);
+		goto release;
+	}
+#undef REALLY_SLOW_IO
+
+	/*
+	 * We should be able to change the 7 LSB of the address port. The
+	 * MSB (busy flag) should be clear initially, set after the write.
+	 */
+	save = inb_p(address + W83781D_ADDR_REG_OFFSET);
+	if (save & 0x80) {
+		pr_debug("Detection failed at step %d\n", 2);
+		goto release;
+	}
+	val = ~save & 0x7f;
+	outb_p(val, address + W83781D_ADDR_REG_OFFSET);
+	if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
+		outb_p(save, address + W83781D_ADDR_REG_OFFSET);
+		pr_debug("Detection failed at step %d\n", 3);
+		goto release;
+	}
+
+	/* We found a device, now see if it could be a W83781D */
+	outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if (val & 0x80) {
+		pr_debug("Detection failed at step %d\n", 4);
+		goto release;
+	}
+	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+	save = inb_p(address + W83781D_DATA_REG_OFFSET);
+	outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if ((!(save & 0x80) && (val != 0xa3))
+	 || ((save & 0x80) && (val != 0x5c))) {
+		pr_debug("Detection failed at step %d\n", 5);
+		goto release;
+	}
+	outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if (val < 0x03 || val > 0x77) {	/* Not a valid I2C address */
+		pr_debug("Detection failed at step %d\n", 6);
+		goto release;
+	}
+
+	/* The busy flag should be clear again */
+	if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
+		pr_debug("Detection failed at step %d\n", 7);
+		goto release;
+	}
+
+	/* Determine the chip type */
+	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+	save = inb_p(address + W83781D_DATA_REG_OFFSET);
+	outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
+	outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if ((val & 0xfe) == 0x10	/* W83781D */
+	 || val == 0x30)		/* W83782D */
+		found = 1;
+
+	if (found)
+		pr_info("Found a %s chip at %#x\n",
+			val == 0x30 ? "W83782D" : "W83781D", (int)address);
+
+ release:
+	for (port--; port >= address; port--)
+		release_region(port, 1);
+	return found;
+}
+
+static int __init
+w83781d_isa_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + W83781D_EXTENT - 1,
+		.name	= "w83781d",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("w83781d", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		pr_err("Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		pr_err("Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+ exit_device_put:
+	platform_device_put(pdev);
+ exit:
+	pdev = NULL;
+	return err;
+}
+
+static int __init
+w83781d_isa_register(void)
+{
+	int res;
+
+	if (w83781d_isa_found(isa_address)) {
+		res = platform_driver_register(&w83781d_isa_driver);
+		if (res)
+			goto exit;
+
+		/* Sets global pdev as a side effect */
+		res = w83781d_isa_device_add(isa_address);
+		if (res)
+			goto exit_unreg_isa_driver;
+	}
+
+	return 0;
+
+exit_unreg_isa_driver:
+	platform_driver_unregister(&w83781d_isa_driver);
+exit:
+	return res;
+}
+
+static void
+w83781d_isa_unregister(void)
+{
+	if (pdev) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&w83781d_isa_driver);
+	}
+}
+#else /* !CONFIG_ISA */
+
+static struct w83781d_data *w83781d_data_if_isa(void)
+{
+	return NULL;
+}
+
+static int
+w83781d_alias_detect(struct i2c_client *client, u8 chipid)
+{
+	return 0;
+}
+
+static int
+w83781d_read_value(struct w83781d_data *data, u16 reg)
+{
+	int res;
+
+	mutex_lock(&data->lock);
+	res = w83781d_read_value_i2c(data, reg);
+	mutex_unlock(&data->lock);
+
+	return res;
+}
+
+static int
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
+{
+	mutex_lock(&data->lock);
+	w83781d_write_value_i2c(data, reg, value);
+	mutex_unlock(&data->lock);
+
+	return 0;
+}
+
+static int __init
+w83781d_isa_register(void)
+{
+	return 0;
+}
+
+static void
+w83781d_isa_unregister(void)
+{
+}
+#endif /* CONFIG_ISA */
+
+static int __init
+sensors_w83781d_init(void)
+{
+	int res;
+
+	/*
+	 * We register the ISA device first, so that we can skip the
+	 * registration of an I2C interface to the same device.
+	 */
+	res = w83781d_isa_register();
+	if (res)
+		goto exit;
+
+	res = i2c_add_driver(&w83781d_driver);
+	if (res)
+		goto exit_unreg_isa;
+
+	return 0;
+
+ exit_unreg_isa:
+	w83781d_isa_unregister();
+ exit:
+	return res;
+}
+
+static void __exit
+sensors_w83781d_exit(void)
+{
+	w83781d_isa_unregister();
+	i2c_del_driver(&w83781d_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	      "Philip Edelbrock <phil@netroedge.com>, "
+	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("W83781D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83781d_init);
+module_exit(sensors_w83781d_exit);
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
new file mode 100644
index 0000000..001df85
--- /dev/null
+++ b/drivers/hwmon/w83791d.c
@@ -0,0 +1,1701 @@
+/*
+ * w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ *
+ * Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
+ *
+ * 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.
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * w83791d	10	5	5	3	0x71	0x5ca3	yes	no
+ *
+ * The w83791d chip appears to be part way between the 83781d and the
+ * 83792d. Thus, this file is derived from both the w83792d.c and
+ * w83781d.c files.
+ *
+ * The w83791g chip is the same as the w83791d but lead-free.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+#define NUMBER_OF_VIN		10
+#define NUMBER_OF_FANIN		5
+#define NUMBER_OF_TEMPIN	3
+#define NUMBER_OF_PWM		5
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+						I2C_CLIENT_END };
+
+/* Insmod parameters */
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients,
+		 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static bool reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset");
+
+static bool init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force extra software initialization");
+
+/* The W83791D registers */
+static const u8 W83791D_REG_IN[NUMBER_OF_VIN] = {
+	0x20,			/* VCOREA in DataSheet */
+	0x21,			/* VINR0 in DataSheet */
+	0x22,			/* +3.3VIN in DataSheet */
+	0x23,			/* VDD5V in DataSheet */
+	0x24,			/* +12VIN in DataSheet */
+	0x25,			/* -12VIN in DataSheet */
+	0x26,			/* -5VIN in DataSheet */
+	0xB0,			/* 5VSB in DataSheet */
+	0xB1,			/* VBAT in DataSheet */
+	0xB2			/* VINR1 in DataSheet */
+};
+
+static const u8 W83791D_REG_IN_MAX[NUMBER_OF_VIN] = {
+	0x2B,			/* VCOREA High Limit in DataSheet */
+	0x2D,			/* VINR0 High Limit in DataSheet */
+	0x2F,			/* +3.3VIN High Limit in DataSheet */
+	0x31,			/* VDD5V High Limit in DataSheet */
+	0x33,			/* +12VIN High Limit in DataSheet */
+	0x35,			/* -12VIN High Limit in DataSheet */
+	0x37,			/* -5VIN High Limit in DataSheet */
+	0xB4,			/* 5VSB High Limit in DataSheet */
+	0xB6,			/* VBAT High Limit in DataSheet */
+	0xB8			/* VINR1 High Limit in DataSheet */
+};
+static const u8 W83791D_REG_IN_MIN[NUMBER_OF_VIN] = {
+	0x2C,			/* VCOREA Low Limit in DataSheet */
+	0x2E,			/* VINR0 Low Limit in DataSheet */
+	0x30,			/* +3.3VIN Low Limit in DataSheet */
+	0x32,			/* VDD5V Low Limit in DataSheet */
+	0x34,			/* +12VIN Low Limit in DataSheet */
+	0x36,			/* -12VIN Low Limit in DataSheet */
+	0x38,			/* -5VIN Low Limit in DataSheet */
+	0xB5,			/* 5VSB Low Limit in DataSheet */
+	0xB7,			/* VBAT Low Limit in DataSheet */
+	0xB9			/* VINR1 Low Limit in DataSheet */
+};
+static const u8 W83791D_REG_FAN[NUMBER_OF_FANIN] = {
+	0x28,			/* FAN 1 Count in DataSheet */
+	0x29,			/* FAN 2 Count in DataSheet */
+	0x2A,			/* FAN 3 Count in DataSheet */
+	0xBA,			/* FAN 4 Count in DataSheet */
+	0xBB,			/* FAN 5 Count in DataSheet */
+};
+static const u8 W83791D_REG_FAN_MIN[NUMBER_OF_FANIN] = {
+	0x3B,			/* FAN 1 Count Low Limit in DataSheet */
+	0x3C,			/* FAN 2 Count Low Limit in DataSheet */
+	0x3D,			/* FAN 3 Count Low Limit in DataSheet */
+	0xBC,			/* FAN 4 Count Low Limit in DataSheet */
+	0xBD,			/* FAN 5 Count Low Limit in DataSheet */
+};
+
+static const u8 W83791D_REG_PWM[NUMBER_OF_PWM] = {
+	0x81,			/* PWM 1 duty cycle register in DataSheet */
+	0x83,			/* PWM 2 duty cycle register in DataSheet */
+	0x94,			/* PWM 3 duty cycle register in DataSheet */
+	0xA0,			/* PWM 4 duty cycle register in DataSheet */
+	0xA1,			/* PWM 5 duty cycle register in DataSheet */
+};
+
+static const u8 W83791D_REG_TEMP_TARGET[3] = {
+	0x85,			/* PWM 1 target temperature for temp 1 */
+	0x86,			/* PWM 2 target temperature for temp 2 */
+	0x96,			/* PWM 3 target temperature for temp 3 */
+};
+
+static const u8 W83791D_REG_TEMP_TOL[2] = {
+	0x87,			/* PWM 1/2 temperature tolerance */
+	0x97,			/* PWM 3 temperature tolerance */
+};
+
+static const u8 W83791D_REG_FAN_CFG[2] = {
+	0x84,			/* FAN 1/2 configuration */
+	0x95,			/* FAN 3 configuration */
+};
+
+static const u8 W83791D_REG_FAN_DIV[3] = {
+	0x47,			/* contains FAN1 and FAN2 Divisor */
+	0x4b,			/* contains FAN3 Divisor */
+	0x5C,			/* contains FAN4 and FAN5 Divisor */
+};
+
+#define W83791D_REG_BANK		0x4E
+#define W83791D_REG_TEMP2_CONFIG	0xC2
+#define W83791D_REG_TEMP3_CONFIG	0xCA
+
+static const u8 W83791D_REG_TEMP1[3] = {
+	0x27,			/* TEMP 1 in DataSheet */
+	0x39,			/* TEMP 1 Over in DataSheet */
+	0x3A,			/* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83791D_REG_TEMP_ADD[2][6] = {
+	{0xC0,			/* TEMP 2 in DataSheet */
+	 0xC1,			/* TEMP 2(0.5 deg) in DataSheet */
+	 0xC5,			/* TEMP 2 Over High part in DataSheet */
+	 0xC6,			/* TEMP 2 Over Low part in DataSheet */
+	 0xC3,			/* TEMP 2 Thyst High part in DataSheet */
+	 0xC4},			/* TEMP 2 Thyst Low part in DataSheet */
+	{0xC8,			/* TEMP 3 in DataSheet */
+	 0xC9,			/* TEMP 3(0.5 deg) in DataSheet */
+	 0xCD,			/* TEMP 3 Over High part in DataSheet */
+	 0xCE,			/* TEMP 3 Over Low part in DataSheet */
+	 0xCB,			/* TEMP 3 Thyst High part in DataSheet */
+	 0xCC}			/* TEMP 3 Thyst Low part in DataSheet */
+};
+
+#define W83791D_REG_BEEP_CONFIG		0x4D
+
+static const u8 W83791D_REG_BEEP_CTRL[3] = {
+	0x56,			/* BEEP Control Register 1 */
+	0x57,			/* BEEP Control Register 2 */
+	0xA3,			/* BEEP Control Register 3 */
+};
+
+#define W83791D_REG_GPIO		0x15
+#define W83791D_REG_CONFIG		0x40
+#define W83791D_REG_VID_FANDIV		0x47
+#define W83791D_REG_DID_VID4		0x49
+#define W83791D_REG_WCHIPID		0x58
+#define W83791D_REG_CHIPMAN		0x4F
+#define W83791D_REG_PIN			0x4B
+#define W83791D_REG_I2C_SUBADDR		0x4A
+
+#define W83791D_REG_ALARM1 0xA9	/* realtime status register1 */
+#define W83791D_REG_ALARM2 0xAA	/* realtime status register2 */
+#define W83791D_REG_ALARM3 0xAB	/* realtime status register3 */
+
+#define W83791D_REG_VBAT		0x5D
+#define W83791D_REG_I2C_ADDR		0x48
+
+/*
+ * The SMBus locks itself. The Winbond W83791D has a bank select register
+ * (index 0x4e), but the driver only accesses registers in bank 0. Since
+ * we don't switch banks, we don't need any special code to handle
+ * locking access between bank switches
+ */
+static inline int w83791d_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/*
+ * The analog voltage inputs have 16mV LSB. Since the sysfs output is
+ * in mV as would be measured on the chip input pin, need to just
+ * multiply/divide by 16 to translate from/to register values.
+ */
+#define IN_TO_REG(val)		(clamp_val((((val) + 8) / 16), 0, 255))
+#define IN_FROM_REG(val)	((val) * 16)
+
+static u8 fan_to_reg(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val, div)	((val) == 0 ? -1 : \
+				((val) == 255 ? 0 : \
+					1350000 / ((val) * (div))))
+
+/* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */
+#define TEMP1_FROM_REG(val)	((val) * 1000)
+#define TEMP1_TO_REG(val)	((val) <= -128000 ? -128 : \
+				 (val) >= 127000 ? 127 : \
+				 (val) < 0 ? ((val) - 500) / 1000 : \
+				 ((val) + 500) / 1000)
+
+/*
+ * for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius
+ * Assumes the top 8 bits are the integral amount and the bottom 8 bits
+ * are the fractional amount. Since we only have 0.5 degree resolution,
+ * the bottom 7 bits will always be zero
+ */
+#define TEMP23_FROM_REG(val)	((val) / 128 * 500)
+#define TEMP23_TO_REG(val)	(DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
+						   127500), 500) * 128)
+
+/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
+#define TARGET_TEMP_TO_REG(val)	DIV_ROUND_CLOSEST(clamp_val((val), 0, 127000), \
+						  1000)
+
+/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
+#define TOL_TEMP_TO_REG(val)	DIV_ROUND_CLOSEST(clamp_val((val), 0, 15000), \
+						  1000)
+
+#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
+#define BEEP_MASK_FROM_REG(val)		((val) & 0xffffff)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+
+static u8 div_to_reg(int nr, long val)
+{
+	int i;
+
+	/* fan divisors max out at 128 */
+	val = clamp_val(val, 1, 128) >> 1;
+	for (i = 0; i < 7; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return (u8) i;
+}
+
+struct w83791d_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* array of 2 pointers to subclients */
+	struct i2c_client *lm75[2];
+
+	/* volts */
+	u8 in[NUMBER_OF_VIN];		/* Register value */
+	u8 in_max[NUMBER_OF_VIN];	/* Register value */
+	u8 in_min[NUMBER_OF_VIN];	/* Register value */
+
+	/* fans */
+	u8 fan[NUMBER_OF_FANIN];	/* Register value */
+	u8 fan_min[NUMBER_OF_FANIN];	/* Register value */
+	u8 fan_div[NUMBER_OF_FANIN];	/* Register encoding, shifted right */
+
+	/* Temperature sensors */
+
+	s8 temp1[3];		/* current, over, thyst */
+	s16 temp_add[2][3];	/* fixed point value. Top 8 bits are the
+				 * integral part, bottom 8 bits are the
+				 * fractional part. We only use the top
+				 * 9 bits as the resolution is only
+				 * to the 0.5 degree C...
+				 * two sensors with three values
+				 * (cur, over, hyst)
+				 */
+
+	/* PWMs */
+	u8 pwm[5];		/* pwm duty cycle */
+	u8 pwm_enable[3];	/* pwm enable status for fan 1-3
+				 * (fan 4-5 only support manual mode)
+				 */
+
+	u8 temp_target[3];	/* pwm 1-3 target temperature */
+	u8 temp_tolerance[3];	/* pwm 1-3 temperature tolerance */
+
+	/* Misc */
+	u32 alarms;		/* realtime status register encoding,combined */
+	u8 beep_enable;		/* Global beep enable */
+	u32 beep_mask;		/* Mask off specific beeps */
+	u8 vid;			/* Register encoding, combined */
+	u8 vrm;			/* hwmon-vid */
+};
+
+static int w83791d_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id);
+static int w83791d_detect(struct i2c_client *client,
+			  struct i2c_board_info *info);
+static int w83791d_remove(struct i2c_client *client);
+
+static int w83791d_read(struct i2c_client *client, u8 reg);
+static int w83791d_write(struct i2c_client *client, u8 reg, u8 value);
+static struct w83791d_data *w83791d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
+#endif
+
+static void w83791d_init_client(struct i2c_client *client);
+
+static const struct i2c_device_id w83791d_id[] = {
+	{ "w83791d", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83791d_id);
+
+static struct i2c_driver w83791d_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name = "w83791d",
+	},
+	.probe		= w83791d_probe,
+	.remove		= w83791d_remove,
+	.id_table	= w83791d_id,
+	.detect		= w83791d_detect,
+	.address_list	= normal_i2c,
+};
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			char *buf) \
+{ \
+	struct sensor_device_attribute *sensor_attr = \
+						to_sensor_dev_attr(attr); \
+	struct w83791d_data *data = w83791d_update_device(dev); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \
+}
+
+show_in_reg(in);
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg(struct device *dev, \
+				struct device_attribute *attr, \
+				const char *buf, size_t count) \
+{ \
+	struct sensor_device_attribute *sensor_attr = \
+						to_sensor_dev_attr(attr); \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct w83791d_data *data = i2c_get_clientdata(client); \
+	int nr = sensor_attr->index; \
+	unsigned long val; \
+	int err = kstrtoul(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = IN_TO_REG(val); \
+	w83791d_write(client, W83791D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	 \
+	return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+static struct sensor_device_attribute sda_in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+	SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+};
+
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr =
+						to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int bitnr = sensor_attr->index;
+
+	return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t store_beep(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr =
+						to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int bitnr = sensor_attr->index;
+	int bytenr = bitnr / 8;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	val = val ? 1 : 0;
+
+	mutex_lock(&data->update_lock);
+
+	data->beep_mask &= ~(0xff << (bytenr * 8));
+	data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
+		<< (bytenr * 8);
+
+	data->beep_mask &= ~(1 << bitnr);
+	data->beep_mask |= val << bitnr;
+
+	w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
+		(data->beep_mask >> (bytenr * 8)) & 0xff);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr =
+						to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int bitnr = sensor_attr->index;
+
+	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+/*
+ * Note: The bitmask for the beep enable/disable is different than
+ * the bitmask for the alarm.
+ */
+static struct sensor_device_attribute sda_in_beep[] = {
+	SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
+	SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
+	SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
+	SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
+	SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
+	SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
+	SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
+	SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
+	SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
+	SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+	SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+	SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+	SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+	SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+	SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+	SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
+	SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
+	SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
+	SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
+	SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
+};
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+				char *buf) \
+{ \
+	struct sensor_device_attribute *sensor_attr = \
+						to_sensor_dev_attr(attr); \
+	struct w83791d_data *data = w83791d_update_device(dev); \
+	int nr = sensor_attr->index; \
+	return sprintf(buf, "%d\n", \
+		FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = fan_to_reg(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long min;
+	u8 tmp_fan_div;
+	u8 fan_div_reg;
+	u8 vbat_reg;
+	int indx = 0;
+	u8 keep_mask = 0;
+	u8 new_shift = 0;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+
+	mutex_lock(&data->update_lock);
+	data->fan_div[nr] = div_to_reg(nr, val);
+
+	switch (nr) {
+	case 0:
+		indx = 0;
+		keep_mask = 0xcf;
+		new_shift = 4;
+		break;
+	case 1:
+		indx = 0;
+		keep_mask = 0x3f;
+		new_shift = 6;
+		break;
+	case 2:
+		indx = 1;
+		keep_mask = 0x3f;
+		new_shift = 6;
+		break;
+	case 3:
+		indx = 2;
+		keep_mask = 0xf8;
+		new_shift = 0;
+		break;
+	case 4:
+		indx = 2;
+		keep_mask = 0x8f;
+		new_shift = 4;
+		break;
+#ifdef DEBUG
+	default:
+		dev_warn(dev, "store_fan_div: Unexpected nr seen: %d\n", nr);
+		count = -EINVAL;
+		goto err_exit;
+#endif
+	}
+
+	fan_div_reg = w83791d_read(client, W83791D_REG_FAN_DIV[indx])
+			& keep_mask;
+	tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask;
+
+	w83791d_write(client, W83791D_REG_FAN_DIV[indx],
+				fan_div_reg | tmp_fan_div);
+
+	/* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */
+	if (nr < 3) {
+		keep_mask = ~(1 << (nr + 5));
+		vbat_reg = w83791d_read(client, W83791D_REG_VBAT)
+				& keep_mask;
+		tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask;
+		w83791d_write(client, W83791D_REG_VBAT,
+				vbat_reg | tmp_fan_div);
+	}
+
+	/* Restore fan_min */
+	data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
+	w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
+
+#ifdef DEBUG
+err_exit:
+#endif
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 1),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 2),
+	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 3),
+	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 4),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 0),
+	SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 1),
+	SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 2),
+	SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 3),
+	SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 4),
+};
+
+static struct sensor_device_attribute sda_fan_beep[] = {
+	SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
+	SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
+	SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
+	SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
+	SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+	SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+	SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+	SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+	SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
+	SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
+};
+
+/* read/write PWMs */
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%u\n", data->pwm[nr]);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = clamp_val(val, 0, 255);
+	w83791d_write(client, W83791D_REG_PWM[nr], data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO,
+			show_pwm, store_pwm, 0),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO,
+			show_pwm, store_pwm, 1),
+	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO,
+			show_pwm, store_pwm, 2),
+	SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO,
+			show_pwm, store_pwm, 3),
+	SENSOR_ATTR(pwm5, S_IWUSR | S_IRUGO,
+			show_pwm, store_pwm, 4),
+};
+
+static ssize_t show_pwmenable(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%u\n", data->pwm_enable[nr] + 1);
+}
+
+static ssize_t store_pwmenable(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	u8 reg_cfg_tmp;
+	u8 reg_idx = 0;
+	u8 val_shift = 0;
+	u8 keep_mask = 0;
+
+	int ret = kstrtoul(buf, 10, &val);
+
+	if (ret || val < 1 || val > 3)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable[nr] = val - 1;
+	switch (nr) {
+	case 0:
+		reg_idx = 0;
+		val_shift = 2;
+		keep_mask = 0xf3;
+		break;
+	case 1:
+		reg_idx = 0;
+		val_shift = 4;
+		keep_mask = 0xcf;
+		break;
+	case 2:
+		reg_idx = 1;
+		val_shift = 2;
+		keep_mask = 0xf3;
+		break;
+	}
+
+	reg_cfg_tmp = w83791d_read(client, W83791D_REG_FAN_CFG[reg_idx]);
+	reg_cfg_tmp = (reg_cfg_tmp & keep_mask) |
+					data->pwm_enable[nr] << val_shift;
+
+	w83791d_write(client, W83791D_REG_FAN_CFG[reg_idx], reg_cfg_tmp);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+static struct sensor_device_attribute sda_pwmenable[] = {
+	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 0),
+	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 1),
+	SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 2),
+};
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t show_temp_target(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_target[nr]));
+}
+
+static ssize_t store_temp_target(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	long val;
+	u8 target_mask;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->temp_target[nr] = TARGET_TEMP_TO_REG(val);
+	target_mask = w83791d_read(client,
+				W83791D_REG_TEMP_TARGET[nr]) & 0x80;
+	w83791d_write(client, W83791D_REG_TEMP_TARGET[nr],
+				data->temp_target[nr] | target_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_temp_target[] = {
+	SENSOR_ATTR(temp1_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 0),
+	SENSOR_ATTR(temp2_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 1),
+	SENSOR_ATTR(temp3_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 2),
+};
+
+static ssize_t show_temp_tolerance(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_tolerance[nr]));
+}
+
+static ssize_t store_temp_tolerance(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	u8 target_mask;
+	u8 reg_idx = 0;
+	u8 val_shift = 0;
+	u8 keep_mask = 0;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	switch (nr) {
+	case 0:
+		reg_idx = 0;
+		val_shift = 0;
+		keep_mask = 0xf0;
+		break;
+	case 1:
+		reg_idx = 0;
+		val_shift = 4;
+		keep_mask = 0x0f;
+		break;
+	case 2:
+		reg_idx = 1;
+		val_shift = 0;
+		keep_mask = 0xf0;
+		break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->temp_tolerance[nr] = TOL_TEMP_TO_REG(val);
+	target_mask = w83791d_read(client,
+			W83791D_REG_TEMP_TOL[reg_idx]) & keep_mask;
+	w83791d_write(client, W83791D_REG_TEMP_TOL[reg_idx],
+			(data->temp_tolerance[nr] << val_shift) | target_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_temp_tolerance[] = {
+	SENSOR_ATTR(temp1_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 0),
+	SENSOR_ATTR(temp2_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 1),
+	SENSOR_ATTR(temp3_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 2),
+};
+
+/* read/write the temperature1, includes measured value and limits */
+static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
+				char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[attr->index]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *devattr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp1[nr] = TEMP1_TO_REG(val);
+	w83791d_write(client, W83791D_REG_TEMP1[nr], data->temp1[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* read/write temperature2-3, includes measured value and limits */
+static ssize_t show_temp23(struct device *dev, struct device_attribute *devattr,
+				char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int nr = attr->nr;
+	int index = attr->index;
+	return sprintf(buf, "%d\n", TEMP23_FROM_REG(data->temp_add[nr][index]));
+}
+
+static ssize_t store_temp23(struct device *dev,
+				struct device_attribute *devattr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+	int nr = attr->nr;
+	int index = attr->index;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_add[nr][index] = TEMP23_TO_REG(val);
+	w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2],
+				data->temp_add[nr][index] >> 8);
+	w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2 + 1],
+				data->temp_add[nr][index] & 0x80);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+	SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+			show_temp1, store_temp1, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 0, 1),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 1, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp1, store_temp1, 0, 2),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 0, 2),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 1, 2),
+};
+
+/*
+ * Note: The bitmask for the beep enable/disable is different than
+ * the bitmask for the alarm.
+ */
+static struct sensor_device_attribute sda_temp_beep[] = {
+	SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
+	SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
+	SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+	SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+	SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+	SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
+
+/* get realtime status of all sensors items: voltage, temp, fan */
+static ssize_t show_alarms_reg(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+/* Beep control */
+
+#define GLOBAL_BEEP_ENABLE_SHIFT	15
+#define GLOBAL_BEEP_ENABLE_MASK		(1 << GLOBAL_BEEP_ENABLE_SHIFT)
+
+static ssize_t show_beep_enable(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%d\n", data->beep_enable);
+}
+
+static ssize_t show_beep_mask(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%d\n", BEEP_MASK_FROM_REG(data->beep_mask));
+}
+
+
+static ssize_t store_beep_mask(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int i;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	/*
+	 * The beep_enable state overrides any enabling request from
+	 * the masks
+	 */
+	data->beep_mask = BEEP_MASK_TO_REG(val) & ~GLOBAL_BEEP_ENABLE_MASK;
+	data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
+
+	val = data->beep_mask;
+
+	for (i = 0; i < 3; i++) {
+		w83791d_write(client, W83791D_REG_BEEP_CTRL[i], (val & 0xff));
+		val >>= 8;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t store_beep_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+
+	data->beep_enable = val ? 1 : 0;
+
+	/* Keep the full mask value in sync with the current enable */
+	data->beep_mask &= ~GLOBAL_BEEP_ENABLE_MASK;
+	data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
+
+	/*
+	 * The global control is in the second beep control register
+	 * so only need to update that register
+	 */
+	val = (data->beep_mask >> 8) & 0xff;
+
+	w83791d_write(client, W83791D_REG_BEEP_CTRL[1], val);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute sda_beep_ctrl[] = {
+	SENSOR_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+			show_beep_enable, store_beep_enable, 0),
+	SENSOR_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+			show_beep_mask, store_beep_mask, 1)
+};
+
+/* cpu voltage regulation information */
+static ssize_t show_vid_reg(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_vrm_reg(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct w83791d_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t store_vrm_reg(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct w83791d_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	/*
+	 * No lock needed as vrm is internal to the driver
+	 * (not read from a chip register) and so is not
+	 * updated in w83791d_update_device()
+	 */
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+#define IN_UNIT_ATTRS(X) \
+	&sda_in_input[X].dev_attr.attr,	\
+	&sda_in_min[X].dev_attr.attr,	\
+	&sda_in_max[X].dev_attr.attr,	\
+	&sda_in_beep[X].dev_attr.attr,	\
+	&sda_in_alarm[X].dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X) \
+	&sda_fan_input[X].dev_attr.attr,	\
+	&sda_fan_min[X].dev_attr.attr,		\
+	&sda_fan_div[X].dev_attr.attr,		\
+	&sda_fan_beep[X].dev_attr.attr,		\
+	&sda_fan_alarm[X].dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+	&sda_temp_input[X].dev_attr.attr,	\
+	&sda_temp_max[X].dev_attr.attr,		\
+	&sda_temp_max_hyst[X].dev_attr.attr,	\
+	&sda_temp_beep[X].dev_attr.attr,	\
+	&sda_temp_alarm[X].dev_attr.attr
+
+static struct attribute *w83791d_attributes[] = {
+	IN_UNIT_ATTRS(0),
+	IN_UNIT_ATTRS(1),
+	IN_UNIT_ATTRS(2),
+	IN_UNIT_ATTRS(3),
+	IN_UNIT_ATTRS(4),
+	IN_UNIT_ATTRS(5),
+	IN_UNIT_ATTRS(6),
+	IN_UNIT_ATTRS(7),
+	IN_UNIT_ATTRS(8),
+	IN_UNIT_ATTRS(9),
+	FAN_UNIT_ATTRS(0),
+	FAN_UNIT_ATTRS(1),
+	FAN_UNIT_ATTRS(2),
+	TEMP_UNIT_ATTRS(0),
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2),
+	&dev_attr_alarms.attr,
+	&sda_beep_ctrl[0].dev_attr.attr,
+	&sda_beep_ctrl[1].dev_attr.attr,
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&sda_pwm[0].dev_attr.attr,
+	&sda_pwm[1].dev_attr.attr,
+	&sda_pwm[2].dev_attr.attr,
+	&sda_pwmenable[0].dev_attr.attr,
+	&sda_pwmenable[1].dev_attr.attr,
+	&sda_pwmenable[2].dev_attr.attr,
+	&sda_temp_target[0].dev_attr.attr,
+	&sda_temp_target[1].dev_attr.attr,
+	&sda_temp_target[2].dev_attr.attr,
+	&sda_temp_tolerance[0].dev_attr.attr,
+	&sda_temp_tolerance[1].dev_attr.attr,
+	&sda_temp_tolerance[2].dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group w83791d_group = {
+	.attrs = w83791d_attributes,
+};
+
+/*
+ * Separate group of attributes for fan/pwm 4-5. Their pins can also be
+ * in use for GPIO in which case their sysfs-interface should not be made
+ * available
+ */
+static struct attribute *w83791d_attributes_fanpwm45[] = {
+	FAN_UNIT_ATTRS(3),
+	FAN_UNIT_ATTRS(4),
+	&sda_pwm[3].dev_attr.attr,
+	&sda_pwm[4].dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group w83791d_group_fanpwm45 = {
+	.attrs = w83791d_attributes_fanpwm45,
+};
+
+static int w83791d_detect_subclients(struct i2c_client *client)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int address = client->addr;
+	int i, id, err;
+	u8 val;
+
+	id = i2c_adapter_id(adapter);
+	if (force_subclients[0] == id && force_subclients[1] == address) {
+		for (i = 2; i <= 3; i++) {
+			if (force_subclients[i] < 0x48 ||
+			    force_subclients[i] > 0x4f) {
+				dev_err(&client->dev,
+					"invalid subclient "
+					"address %d; must be 0x48-0x4f\n",
+					force_subclients[i]);
+				err = -ENODEV;
+				goto error_sc_0;
+			}
+		}
+		w83791d_write(client, W83791D_REG_I2C_SUBADDR,
+					(force_subclients[2] & 0x07) |
+					((force_subclients[3] & 0x07) << 4));
+	}
+
+	val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
+	if (!(val & 0x08))
+		data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+	if (!(val & 0x80)) {
+		if ((data->lm75[0] != NULL) &&
+				((val & 0x7) == ((val >> 4) & 0x7))) {
+			dev_err(&client->dev,
+				"duplicate addresses 0x%x, "
+				"use force_subclient\n",
+				data->lm75[0]->addr);
+			err = -ENODEV;
+			goto error_sc_1;
+		}
+		data->lm75[1] = i2c_new_dummy(adapter,
+					      0x48 + ((val >> 4) & 0x7));
+	}
+
+	return 0;
+
+/* Undo inits in case of errors */
+
+error_sc_1:
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+error_sc_0:
+	return err;
+}
+
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83791d_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int val1, val2;
+	unsigned short address = client->addr;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80)
+		return -ENODEV;
+
+	val1 = w83791d_read(client, W83791D_REG_BANK);
+	val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+	/* Check for Winbond ID if in bank 0 */
+	if (!(val1 & 0x07)) {
+		if ((!(val1 & 0x80) && val2 != 0xa3) ||
+		    ((val1 & 0x80) && val2 != 0x5c)) {
+			return -ENODEV;
+		}
+	}
+	/*
+	 * If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
+	 * should match
+	 */
+	if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address)
+		return -ENODEV;
+
+	/* We want bank 0 and Vendor ID high byte */
+	val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78;
+	w83791d_write(client, W83791D_REG_BANK, val1 | 0x80);
+
+	/* Verify it is a Winbond w83791d */
+	val1 = w83791d_read(client, W83791D_REG_WCHIPID);
+	val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+	if (val1 != 0x71 || val2 != 0x5c)
+		return -ENODEV;
+
+	strlcpy(info->type, "w83791d", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int w83791d_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct w83791d_data *data;
+	struct device *dev = &client->dev;
+	int i, err;
+	u8 has_fanpwm45;
+
+#ifdef DEBUG
+	int val1;
+	val1 = w83791d_read(client, W83791D_REG_DID_VID4);
+	dev_dbg(dev, "Device ID version: %d.%d (0x%02x)\n",
+			(val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
+#endif
+
+	data = devm_kzalloc(&client->dev, sizeof(struct w83791d_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	err = w83791d_detect_subclients(client);
+	if (err)
+		return err;
+
+	/* Initialize the chip */
+	w83791d_init_client(client);
+
+	/*
+	 * If the fan_div is changed, make sure there is a rational
+	 * fan_min in place
+	 */
+	for (i = 0; i < NUMBER_OF_FANIN; i++)
+		data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &w83791d_group);
+	if (err)
+		goto error3;
+
+	/* Check if pins of fan/pwm 4-5 are in use as GPIO */
+	has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10;
+	if (has_fanpwm45) {
+		err = sysfs_create_group(&client->dev.kobj,
+					 &w83791d_group_fanpwm45);
+		if (err)
+			goto error4;
+	}
+
+	/* Everything is ready, now register the working device */
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error5;
+	}
+
+	return 0;
+
+error5:
+	if (has_fanpwm45)
+		sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
+error4:
+	sysfs_remove_group(&client->dev.kobj, &w83791d_group);
+error3:
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+	return err;
+}
+
+static int w83791d_remove(struct i2c_client *client)
+{
+	struct w83791d_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &w83791d_group);
+
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+
+	return 0;
+}
+
+static void w83791d_init_client(struct i2c_client *client)
+{
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	u8 tmp;
+	u8 old_beep;
+
+	/*
+	 * The difference between reset and init is that reset
+	 * does a hard reset of the chip via index 0x40, bit 7,
+	 * but init simply forces certain registers to have "sane"
+	 * values. The hope is that the BIOS has done the right
+	 * thing (which is why the default is reset=0, init=0),
+	 * but if not, reset is the hard hammer and init
+	 * is the soft mallet both of which are trying to whack
+	 * things into place...
+	 * NOTE: The data sheet makes a distinction between
+	 * "power on defaults" and "reset by MR". As far as I can tell,
+	 * the hard reset puts everything into a power-on state so I'm
+	 * not sure what "reset by MR" means or how it can happen.
+	 */
+	if (reset || init) {
+		/* keep some BIOS settings when we... */
+		old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG);
+
+		if (reset) {
+			/* ... reset the chip and ... */
+			w83791d_write(client, W83791D_REG_CONFIG, 0x80);
+		}
+
+		/* ... disable power-on abnormal beep */
+		w83791d_write(client, W83791D_REG_BEEP_CONFIG, old_beep | 0x80);
+
+		/* disable the global beep (not done by hard reset) */
+		tmp = w83791d_read(client, W83791D_REG_BEEP_CTRL[1]);
+		w83791d_write(client, W83791D_REG_BEEP_CTRL[1], tmp & 0xef);
+
+		if (init) {
+			/* Make sure monitoring is turned on for add-ons */
+			tmp = w83791d_read(client, W83791D_REG_TEMP2_CONFIG);
+			if (tmp & 1) {
+				w83791d_write(client, W83791D_REG_TEMP2_CONFIG,
+					tmp & 0xfe);
+			}
+
+			tmp = w83791d_read(client, W83791D_REG_TEMP3_CONFIG);
+			if (tmp & 1) {
+				w83791d_write(client, W83791D_REG_TEMP3_CONFIG,
+					tmp & 0xfe);
+			}
+
+			/* Start monitoring */
+			tmp = w83791d_read(client, W83791D_REG_CONFIG) & 0xf7;
+			w83791d_write(client, W83791D_REG_CONFIG, tmp | 0x01);
+		}
+	}
+
+	data->vrm = vid_which_vrm();
+}
+
+static struct w83791d_data *w83791d_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int i, j;
+	u8 reg_array_tmp[3];
+	u8 vbat_reg;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + (HZ * 3))
+			|| !data->valid) {
+		dev_dbg(dev, "Starting w83791d device update\n");
+
+		/* Update the voltages measured value and limits */
+		for (i = 0; i < NUMBER_OF_VIN; i++) {
+			data->in[i] = w83791d_read(client,
+						W83791D_REG_IN[i]);
+			data->in_max[i] = w83791d_read(client,
+						W83791D_REG_IN_MAX[i]);
+			data->in_min[i] = w83791d_read(client,
+						W83791D_REG_IN_MIN[i]);
+		}
+
+		/* Update the fan counts and limits */
+		for (i = 0; i < NUMBER_OF_FANIN; i++) {
+			/* Update the Fan measured value and limits */
+			data->fan[i] = w83791d_read(client,
+						W83791D_REG_FAN[i]);
+			data->fan_min[i] = w83791d_read(client,
+						W83791D_REG_FAN_MIN[i]);
+		}
+
+		/* Update the fan divisor */
+		for (i = 0; i < 3; i++) {
+			reg_array_tmp[i] = w83791d_read(client,
+						W83791D_REG_FAN_DIV[i]);
+		}
+		data->fan_div[0] = (reg_array_tmp[0] >> 4) & 0x03;
+		data->fan_div[1] = (reg_array_tmp[0] >> 6) & 0x03;
+		data->fan_div[2] = (reg_array_tmp[1] >> 6) & 0x03;
+		data->fan_div[3] = reg_array_tmp[2] & 0x07;
+		data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
+
+		/*
+		 * The fan divisor for fans 0-2 get bit 2 from
+		 * bits 5-7 respectively of vbat register
+		 */
+		vbat_reg = w83791d_read(client, W83791D_REG_VBAT);
+		for (i = 0; i < 3; i++)
+			data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
+
+		/* Update PWM duty cycle */
+		for (i = 0; i < NUMBER_OF_PWM; i++) {
+			data->pwm[i] =  w83791d_read(client,
+						W83791D_REG_PWM[i]);
+		}
+
+		/* Update PWM enable status */
+		for (i = 0; i < 2; i++) {
+			reg_array_tmp[i] = w83791d_read(client,
+						W83791D_REG_FAN_CFG[i]);
+		}
+		data->pwm_enable[0] = (reg_array_tmp[0] >> 2) & 0x03;
+		data->pwm_enable[1] = (reg_array_tmp[0] >> 4) & 0x03;
+		data->pwm_enable[2] = (reg_array_tmp[1] >> 2) & 0x03;
+
+		/* Update PWM target temperature */
+		for (i = 0; i < 3; i++) {
+			data->temp_target[i] = w83791d_read(client,
+				W83791D_REG_TEMP_TARGET[i]) & 0x7f;
+		}
+
+		/* Update PWM temperature tolerance */
+		for (i = 0; i < 2; i++) {
+			reg_array_tmp[i] = w83791d_read(client,
+					W83791D_REG_TEMP_TOL[i]);
+		}
+		data->temp_tolerance[0] = reg_array_tmp[0] & 0x0f;
+		data->temp_tolerance[1] = (reg_array_tmp[0] >> 4) & 0x0f;
+		data->temp_tolerance[2] = reg_array_tmp[1] & 0x0f;
+
+		/* Update the first temperature sensor */
+		for (i = 0; i < 3; i++) {
+			data->temp1[i] = w83791d_read(client,
+						W83791D_REG_TEMP1[i]);
+		}
+
+		/* Update the rest of the temperature sensors */
+		for (i = 0; i < 2; i++) {
+			for (j = 0; j < 3; j++) {
+				data->temp_add[i][j] =
+					(w83791d_read(client,
+					W83791D_REG_TEMP_ADD[i][j * 2]) << 8) |
+					w83791d_read(client,
+					W83791D_REG_TEMP_ADD[i][j * 2 + 1]);
+			}
+		}
+
+		/* Update the realtime status */
+		data->alarms =
+			w83791d_read(client, W83791D_REG_ALARM1) +
+			(w83791d_read(client, W83791D_REG_ALARM2) << 8) +
+			(w83791d_read(client, W83791D_REG_ALARM3) << 16);
+
+		/* Update the beep configuration information */
+		data->beep_mask =
+			w83791d_read(client, W83791D_REG_BEEP_CTRL[0]) +
+			(w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
+			(w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
+
+		/* Extract global beep enable flag */
+		data->beep_enable =
+			(data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
+
+		/* Update the cpu voltage information */
+		i = w83791d_read(client, W83791D_REG_VID_FANDIV);
+		data->vid = i & 0x0f;
+		data->vid |= (w83791d_read(client, W83791D_REG_DID_VID4) & 0x01)
+				<< 4;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+#ifdef DEBUG
+	w83791d_print_debug(data, dev);
+#endif
+
+	return data;
+}
+
+#ifdef DEBUG
+static void w83791d_print_debug(struct w83791d_data *data, struct device *dev)
+{
+	int i = 0, j = 0;
+
+	dev_dbg(dev, "======Start of w83791d debug values======\n");
+	dev_dbg(dev, "%d set of Voltages: ===>\n", NUMBER_OF_VIN);
+	for (i = 0; i < NUMBER_OF_VIN; i++) {
+		dev_dbg(dev, "vin[%d] is:     0x%02x\n", i, data->in[i]);
+		dev_dbg(dev, "vin[%d] min is: 0x%02x\n", i, data->in_min[i]);
+		dev_dbg(dev, "vin[%d] max is: 0x%02x\n", i, data->in_max[i]);
+	}
+	dev_dbg(dev, "%d set of Fan Counts/Divisors: ===>\n", NUMBER_OF_FANIN);
+	for (i = 0; i < NUMBER_OF_FANIN; i++) {
+		dev_dbg(dev, "fan[%d] is:     0x%02x\n", i, data->fan[i]);
+		dev_dbg(dev, "fan[%d] min is: 0x%02x\n", i, data->fan_min[i]);
+		dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]);
+	}
+
+	/*
+	 * temperature math is signed, but only print out the
+	 * bits that matter
+	 */
+	dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN);
+	for (i = 0; i < 3; i++)
+		dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]);
+	for (i = 0; i < 2; i++) {
+		for (j = 0; j < 3; j++) {
+			dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j,
+				(u16) data->temp_add[i][j]);
+		}
+	}
+
+	dev_dbg(dev, "Misc Information: ===>\n");
+	dev_dbg(dev, "alarm is:     0x%08x\n", data->alarms);
+	dev_dbg(dev, "beep_mask is: 0x%08x\n", data->beep_mask);
+	dev_dbg(dev, "beep_enable is: %d\n", data->beep_enable);
+	dev_dbg(dev, "vid is: 0x%02x\n", data->vid);
+	dev_dbg(dev, "vrm is: 0x%02x\n", data->vrm);
+	dev_dbg(dev, "=======End of w83791d debug values========\n");
+	dev_dbg(dev, "\n");
+}
+#endif
+
+module_i2c_driver(w83791d_driver);
+
+MODULE_AUTHOR("Charles Spirakis <bezaur@gmail.com>");
+MODULE_DESCRIPTION("W83791D driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
new file mode 100644
index 0000000..0a8bce7
--- /dev/null
+++ b/drivers/hwmon/w83792d.c
@@ -0,0 +1,1686 @@
+/*
+ * w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	       monitoring
+ * Copyright (C) 2004, 2005 Winbond Electronics Corp.
+ *			    Shane Huang,
+ *			    Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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.
+ *
+ * Note:
+ * 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver.
+ * 2. This driver is only for Winbond W83792D C version device, there
+ *     are also some motherboards with B version W83792D device. The
+ *     calculation method to in6-in7(measured value, limits) is a little
+ *     different between C and B version. C or B version can be identified
+ *     by CR[0x49h].
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * w83792d	9	7	7	3	0x7a	0x5ca3	yes	no
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.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>
+#include <linux/jiffies.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+						I2C_CLIENT_END };
+
+/* Insmod parameters */
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients,
+		 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static bool init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force chip initialization");
+
+/* The W83792D registers */
+static const u8 W83792D_REG_IN[9] = {
+	0x20,	/* Vcore A in DataSheet */
+	0x21,	/* Vcore B in DataSheet */
+	0x22,	/* VIN0 in DataSheet */
+	0x23,	/* VIN1 in DataSheet */
+	0x24,	/* VIN2 in DataSheet */
+	0x25,	/* VIN3 in DataSheet */
+	0x26,	/* 5VCC in DataSheet */
+	0xB0,	/* 5VSB in DataSheet */
+	0xB1	/* VBAT in DataSheet */
+};
+#define W83792D_REG_LOW_BITS1 0x3E  /* Low Bits I in DataSheet */
+#define W83792D_REG_LOW_BITS2 0x3F  /* Low Bits II in DataSheet */
+static const u8 W83792D_REG_IN_MAX[9] = {
+	0x2B,	/* Vcore A High Limit in DataSheet */
+	0x2D,	/* Vcore B High Limit in DataSheet */
+	0x2F,	/* VIN0 High Limit in DataSheet */
+	0x31,	/* VIN1 High Limit in DataSheet */
+	0x33,	/* VIN2 High Limit in DataSheet */
+	0x35,	/* VIN3 High Limit in DataSheet */
+	0x37,	/* 5VCC High Limit in DataSheet */
+	0xB4,	/* 5VSB High Limit in DataSheet */
+	0xB6	/* VBAT High Limit in DataSheet */
+};
+static const u8 W83792D_REG_IN_MIN[9] = {
+	0x2C,	/* Vcore A Low Limit in DataSheet */
+	0x2E,	/* Vcore B Low Limit in DataSheet */
+	0x30,	/* VIN0 Low Limit in DataSheet */
+	0x32,	/* VIN1 Low Limit in DataSheet */
+	0x34,	/* VIN2 Low Limit in DataSheet */
+	0x36,	/* VIN3 Low Limit in DataSheet */
+	0x38,	/* 5VCC Low Limit in DataSheet */
+	0xB5,	/* 5VSB Low Limit in DataSheet */
+	0xB7	/* VBAT Low Limit in DataSheet */
+};
+static const u8 W83792D_REG_FAN[7] = {
+	0x28,	/* FAN 1 Count in DataSheet */
+	0x29,	/* FAN 2 Count in DataSheet */
+	0x2A,	/* FAN 3 Count in DataSheet */
+	0xB8,	/* FAN 4 Count in DataSheet */
+	0xB9,	/* FAN 5 Count in DataSheet */
+	0xBA,	/* FAN 6 Count in DataSheet */
+	0xBE	/* FAN 7 Count in DataSheet */
+};
+static const u8 W83792D_REG_FAN_MIN[7] = {
+	0x3B,	/* FAN 1 Count Low Limit in DataSheet */
+	0x3C,	/* FAN 2 Count Low Limit in DataSheet */
+	0x3D,	/* FAN 3 Count Low Limit in DataSheet */
+	0xBB,	/* FAN 4 Count Low Limit in DataSheet */
+	0xBC,	/* FAN 5 Count Low Limit in DataSheet */
+	0xBD,	/* FAN 6 Count Low Limit in DataSheet */
+	0xBF	/* FAN 7 Count Low Limit in DataSheet */
+};
+#define W83792D_REG_FAN_CFG 0x84	/* FAN Configuration in DataSheet */
+static const u8 W83792D_REG_FAN_DIV[4] = {
+	0x47,	/* contains FAN2 and FAN1 Divisor */
+	0x5B,	/* contains FAN4 and FAN3 Divisor */
+	0x5C,	/* contains FAN6 and FAN5 Divisor */
+	0x9E	/* contains FAN7 Divisor. */
+};
+static const u8 W83792D_REG_PWM[7] = {
+	0x81,	/* FAN 1 Duty Cycle, be used to control */
+	0x83,	/* FAN 2 Duty Cycle, be used to control */
+	0x94,	/* FAN 3 Duty Cycle, be used to control */
+	0xA3,	/* FAN 4 Duty Cycle, be used to control */
+	0xA4,	/* FAN 5 Duty Cycle, be used to control */
+	0xA5,	/* FAN 6 Duty Cycle, be used to control */
+	0xA6	/* FAN 7 Duty Cycle, be used to control */
+};
+#define W83792D_REG_BANK		0x4E
+#define W83792D_REG_TEMP2_CONFIG	0xC2
+#define W83792D_REG_TEMP3_CONFIG	0xCA
+
+static const u8 W83792D_REG_TEMP1[3] = {
+	0x27,	/* TEMP 1 in DataSheet */
+	0x39,	/* TEMP 1 Over in DataSheet */
+	0x3A,	/* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83792D_REG_TEMP_ADD[2][6] = {
+	{ 0xC0,		/* TEMP 2 in DataSheet */
+	  0xC1,		/* TEMP 2(0.5 deg) in DataSheet */
+	  0xC5,		/* TEMP 2 Over High part in DataSheet */
+	  0xC6,		/* TEMP 2 Over Low part in DataSheet */
+	  0xC3,		/* TEMP 2 Thyst High part in DataSheet */
+	  0xC4 },	/* TEMP 2 Thyst Low part in DataSheet */
+	{ 0xC8,		/* TEMP 3 in DataSheet */
+	  0xC9,		/* TEMP 3(0.5 deg) in DataSheet */
+	  0xCD,		/* TEMP 3 Over High part in DataSheet */
+	  0xCE,		/* TEMP 3 Over Low part in DataSheet */
+	  0xCB,		/* TEMP 3 Thyst High part in DataSheet */
+	  0xCC }	/* TEMP 3 Thyst Low part in DataSheet */
+};
+
+static const u8 W83792D_REG_THERMAL[3] = {
+	0x85,	/* SmartFanI: Fan1 target value */
+	0x86,	/* SmartFanI: Fan2 target value */
+	0x96	/* SmartFanI: Fan3 target value */
+};
+
+static const u8 W83792D_REG_TOLERANCE[3] = {
+	0x87,	/* (bit3-0)SmartFan Fan1 tolerance */
+	0x87,	/* (bit7-4)SmartFan Fan2 tolerance */
+	0x97	/* (bit3-0)SmartFan Fan3 tolerance */
+};
+
+static const u8 W83792D_REG_POINTS[3][4] = {
+	{ 0x85,		/* SmartFanII: Fan1 temp point 1 */
+	  0xE3,		/* SmartFanII: Fan1 temp point 2 */
+	  0xE4,		/* SmartFanII: Fan1 temp point 3 */
+	  0xE5 },	/* SmartFanII: Fan1 temp point 4 */
+	{ 0x86,		/* SmartFanII: Fan2 temp point 1 */
+	  0xE6,		/* SmartFanII: Fan2 temp point 2 */
+	  0xE7,		/* SmartFanII: Fan2 temp point 3 */
+	  0xE8 },	/* SmartFanII: Fan2 temp point 4 */
+	{ 0x96,		/* SmartFanII: Fan3 temp point 1 */
+	  0xE9,		/* SmartFanII: Fan3 temp point 2 */
+	  0xEA,		/* SmartFanII: Fan3 temp point 3 */
+	  0xEB }	/* SmartFanII: Fan3 temp point 4 */
+};
+
+static const u8 W83792D_REG_LEVELS[3][4] = {
+	{ 0x88,		/* (bit3-0) SmartFanII: Fan1 Non-Stop */
+	  0x88,		/* (bit7-4) SmartFanII: Fan1 Level 1 */
+	  0xE0,		/* (bit7-4) SmartFanII: Fan1 Level 2 */
+	  0xE0 },	/* (bit3-0) SmartFanII: Fan1 Level 3 */
+	{ 0x89,		/* (bit3-0) SmartFanII: Fan2 Non-Stop */
+	  0x89,		/* (bit7-4) SmartFanII: Fan2 Level 1 */
+	  0xE1,		/* (bit7-4) SmartFanII: Fan2 Level 2 */
+	  0xE1 },	/* (bit3-0) SmartFanII: Fan2 Level 3 */
+	{ 0x98,		/* (bit3-0) SmartFanII: Fan3 Non-Stop */
+	  0x98,		/* (bit7-4) SmartFanII: Fan3 Level 1 */
+	  0xE2,		/* (bit7-4) SmartFanII: Fan3 Level 2 */
+	  0xE2 }	/* (bit3-0) SmartFanII: Fan3 Level 3 */
+};
+
+#define W83792D_REG_GPIO_EN		0x1A
+#define W83792D_REG_CONFIG		0x40
+#define W83792D_REG_VID_FANDIV		0x47
+#define W83792D_REG_CHIPID		0x49
+#define W83792D_REG_WCHIPID		0x58
+#define W83792D_REG_CHIPMAN		0x4F
+#define W83792D_REG_PIN			0x4B
+#define W83792D_REG_I2C_SUBADDR		0x4A
+
+#define W83792D_REG_ALARM1 0xA9		/* realtime status register1 */
+#define W83792D_REG_ALARM2 0xAA		/* realtime status register2 */
+#define W83792D_REG_ALARM3 0xAB		/* realtime status register3 */
+#define W83792D_REG_CHASSIS 0x42	/* Bit 5: Case Open status bit */
+#define W83792D_REG_CHASSIS_CLR 0x44	/* Bit 7: Case Open CLR_CHS/Reset bit */
+
+/* control in0/in1 's limit modifiability */
+#define W83792D_REG_VID_IN_B		0x17
+
+#define W83792D_REG_VBAT		0x5D
+#define W83792D_REG_I2C_ADDR		0x48
+
+/*
+ * Conversions. Rounding and limit checking is only done on the TO_REG
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ * Fixing this is just not worth it.
+ */
+#define IN_FROM_REG(nr, val) (((nr) <= 1) ? ((val) * 2) : \
+		((((nr) == 6) || ((nr) == 7)) ? ((val) * 6) : ((val) * 4)))
+#define IN_TO_REG(nr, val) (((nr) <= 1) ? ((val) / 2) : \
+		((((nr) == 6) || ((nr) == 7)) ? ((val) / 6) : ((val) / 4)))
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val, div)	((val) == 0   ? -1 : \
+				((val) == 255 ? 0 : \
+						1350000 / ((val) * (div))))
+
+/* for temp1 */
+#define TEMP1_TO_REG(val)	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+						      : (val)) / 1000, 0, 0xff))
+#define TEMP1_FROM_REG(val)	(((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+/* for temp2 and temp3, because they need additional resolution */
+#define TEMP_ADD_FROM_REG(val1, val2) \
+	((((val1) & 0x80 ? (val1)-0x100 \
+		: (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
+#define TEMP_ADD_TO_REG_HIGH(val) \
+	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 : (val)) / 1000, 0, 0xff))
+#define TEMP_ADD_TO_REG_LOW(val)	((val%1000) ? 0x80 : 0x00)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+	int i;
+	val = clamp_val(val, 1, 128) >> 1;
+	for (i = 0; i < 7; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return (u8)i;
+}
+
+struct w83792d_data {
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* array of 2 pointers to subclients */
+	struct i2c_client *lm75[2];
+
+	u8 in[9];		/* Register value */
+	u8 in_max[9];		/* Register value */
+	u8 in_min[9];		/* Register value */
+	u16 low_bits;		/* Additional resolution to voltage in6-0 */
+	u8 fan[7];		/* Register value */
+	u8 fan_min[7];		/* Register value */
+	u8 temp1[3];		/* current, over, thyst */
+	u8 temp_add[2][6];	/* Register value */
+	u8 fan_div[7];		/* Register encoding, shifted right */
+	u8 pwm[7];		/* The 7 PWM outputs */
+	u8 pwmenable[3];
+	u32 alarms;		/* realtime status register encoding,combined */
+	u8 chassis;		/* Chassis status */
+	u8 thermal_cruise[3];	/* Smart FanI: Fan1,2,3 target value */
+	u8 tolerance[3];	/* Fan1,2,3 tolerance(Smart Fan I/II) */
+	u8 sf2_points[3][4];	/* Smart FanII: Fan1,2,3 temperature points */
+	u8 sf2_levels[3][4];	/* Smart FanII: Fan1,2,3 duty cycle levels */
+};
+
+static int w83792d_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id);
+static int w83792d_detect(struct i2c_client *client,
+			  struct i2c_board_info *info);
+static int w83792d_remove(struct i2c_client *client);
+static struct w83792d_data *w83792d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
+#endif
+
+static void w83792d_init_client(struct i2c_client *client);
+
+static const struct i2c_device_id w83792d_id[] = {
+	{ "w83792d", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83792d_id);
+
+static struct i2c_driver w83792d_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name = "w83792d",
+	},
+	.probe		= w83792d_probe,
+	.remove		= w83792d_remove,
+	.id_table	= w83792d_id,
+	.detect		= w83792d_detect,
+	.address_list	= normal_i2c,
+};
+
+static inline long in_count_from_reg(int nr, struct w83792d_data *data)
+{
+	/* in7 and in8 do not have low bits, but the formula still works */
+	return (data->in[nr] << 2) | ((data->low_bits >> (2 * nr)) & 0x03);
+}
+
+/*
+ * The SMBus locks itself. The Winbond W83792D chip has a bank register,
+ * but the driver only accesses registers in bank 0, so we don't have
+ * to switch banks and lock access between switches.
+ */
+static inline int w83792d_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int
+w83792d_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       IN_FROM_REG(nr, in_count_from_reg(nr, data)));
+}
+
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			char *buf) \
+{ \
+	struct sensor_device_attribute *sensor_attr \
+		= to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	struct w83792d_data *data = w83792d_update_device(dev); \
+	return sprintf(buf, "%ld\n", \
+		       (long)(IN_FROM_REG(nr, data->reg[nr]) * 4)); \
+}
+
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg(struct device *dev, \
+				struct device_attribute *attr, \
+				const char *buf, size_t count) \
+{ \
+	struct sensor_device_attribute *sensor_attr \
+			= to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct w83792d_data *data = i2c_get_clientdata(client); \
+	unsigned long val; \
+	int err = kstrtoul(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = clamp_val(IN_TO_REG(nr, val) / 4, 0, 255); \
+	w83792d_write_value(client, W83792D_REG_IN_##REG[nr], \
+			    data->in_##reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	 \
+	return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			char *buf) \
+{ \
+	struct sensor_device_attribute *sensor_attr \
+			= to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index - 1; \
+	struct w83792d_data *data = w83792d_update_device(dev); \
+	return sprintf(buf, "%d\n", \
+		FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
+				data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	unsigned long min;
+	/*u8 reg;*/
+	u8 fan_div_reg = 0;
+	u8 tmp_fan_div;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/* Save fan_min */
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	data->fan_div[nr] = DIV_TO_REG(val);
+
+	fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]);
+	fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8;
+	tmp_fan_div = (nr & 0x01) ? (((data->fan_div[nr]) << 4) & 0x70)
+					: ((data->fan_div[nr]) & 0x07);
+	w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1],
+					fan_div_reg | tmp_fan_div);
+
+	/* Restore fan_min */
+	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* read/write the temperature1, includes measured value and limits */
+
+static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[nr]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp1[nr] = TEMP1_TO_REG(val);
+	w83792d_write_value(client, W83792D_REG_TEMP1[nr],
+		data->temp1[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* read/write the temperature2-3, includes measured value and limits */
+
+static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		(long)TEMP_ADD_FROM_REG(data->temp_add[nr][index],
+			data->temp_add[nr][index+1]));
+}
+
+static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
+	data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
+	w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
+		data->temp_add[nr][index]);
+	w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
+		data->temp_add[nr][index+1]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* get realtime status of all sensors items: voltage, temp, fan */
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", (data->alarms >> nr) & 1);
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", (data->pwm[nr] & 0x0f) << 4);
+}
+
+static ssize_t
+show_pwmenable(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	long pwm_enable_tmp = 1;
+
+	switch (data->pwmenable[nr]) {
+	case 0:
+		pwm_enable_tmp = 1; /* manual mode */
+		break;
+	case 1:
+		pwm_enable_tmp = 3; /*thermal cruise/Smart Fan I */
+		break;
+	case 2:
+		pwm_enable_tmp = 2; /* Smart Fan II */
+		break;
+	}
+
+	return sprintf(buf, "%ld\n", pwm_enable_tmp);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = clamp_val(val, 0, 255) >> 4;
+
+	mutex_lock(&data->update_lock);
+	val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0;
+	data->pwm[nr] = val;
+	w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+store_pwmenable(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val < 1 || val > 3)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 1:
+		data->pwmenable[nr] = 0; /* manual mode */
+		break;
+	case 2:
+		data->pwmenable[nr] = 2; /* Smart Fan II */
+		break;
+	case 3:
+		data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
+		break;
+	}
+	cfg1_tmp = data->pwmenable[0];
+	cfg2_tmp = (data->pwmenable[1]) << 2;
+	cfg3_tmp = (data->pwmenable[2]) << 4;
+	cfg4_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG) & 0xc0;
+	fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
+	w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm[nr] >> 7);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = w83792d_read_value(client, W83792D_REG_PWM[nr]);
+	if (val) {			/* PWM mode */
+		data->pwm[nr] |= 0x80;
+	} else {			/* DC mode */
+		data->pwm[nr] &= 0x7f;
+	}
+	w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_chassis_clear(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n", data->chassis);
+}
+
+static ssize_t
+store_chassis_clear(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	u8 reg;
+
+	if (kstrtoul(buf, 10, &val) || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	reg = w83792d_read_value(client, W83792D_REG_CHASSIS_CLR);
+	w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, reg | 0x80);
+	data->valid = 0;		/* Force cache refresh */
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t
+show_thermal_cruise(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)data->thermal_cruise[nr-1]);
+}
+
+static ssize_t
+store_thermal_cruise(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	u8 target_tmp = 0, target_mask = 0;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	target_tmp = val;
+	target_tmp = target_tmp & 0x7f;
+	mutex_lock(&data->update_lock);
+	target_mask = w83792d_read_value(client,
+					 W83792D_REG_THERMAL[nr]) & 0x80;
+	data->thermal_cruise[nr] = clamp_val(target_tmp, 0, 255);
+	w83792d_write_value(client, W83792D_REG_THERMAL[nr],
+		(data->thermal_cruise[nr]) | target_mask);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)data->tolerance[nr-1]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	u8 tol_tmp, tol_mask;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	tol_mask = w83792d_read_value(client,
+		W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
+	tol_tmp = clamp_val(val, 0, 15);
+	tol_tmp &= 0x0f;
+	data->tolerance[nr] = tol_tmp;
+	if (nr == 1)
+		tol_tmp <<= 4;
+	w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
+		tol_mask | tol_tmp);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* For Smart Fan II */
+static ssize_t
+show_sf2_point(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)data->sf2_points[index-1][nr-1]);
+}
+
+static ssize_t
+store_sf2_point(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr - 1;
+	int index = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	u8 mask_tmp = 0;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->sf2_points[index][nr] = clamp_val(val, 0, 127);
+	mask_tmp = w83792d_read_value(client,
+					W83792D_REG_POINTS[index][nr]) & 0x80;
+	w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
+		mask_tmp|data->sf2_points[index][nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_sf2_level(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83792d_data *data = w83792d_update_device(dev);
+	return sprintf(buf, "%d\n",
+			(((data->sf2_levels[index-1][nr]) * 100) / 15));
+}
+
+static ssize_t
+store_sf2_level(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr
+	  = to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index - 1;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	u8 mask_tmp = 0, level_tmp = 0;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->sf2_levels[index][nr] = clamp_val((val * 15) / 100, 0, 15);
+	mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
+		& ((nr == 3) ? 0xf0 : 0x0f);
+	if (nr == 3)
+		level_tmp = data->sf2_levels[index][nr];
+	else
+		level_tmp = data->sf2_levels[index][nr] << 4;
+	w83792d_write_value(client, W83792D_REG_LEVELS[index][nr],
+			    level_tmp | mask_tmp);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static int
+w83792d_detect_subclients(struct i2c_client *new_client)
+{
+	int i, id, err;
+	int address = new_client->addr;
+	u8 val;
+	struct i2c_adapter *adapter = new_client->adapter;
+	struct w83792d_data *data = i2c_get_clientdata(new_client);
+
+	id = i2c_adapter_id(adapter);
+	if (force_subclients[0] == id && force_subclients[1] == address) {
+		for (i = 2; i <= 3; i++) {
+			if (force_subclients[i] < 0x48 ||
+			    force_subclients[i] > 0x4f) {
+				dev_err(&new_client->dev,
+					"invalid subclient address %d; must be 0x48-0x4f\n",
+					force_subclients[i]);
+				err = -ENODEV;
+				goto ERROR_SC_0;
+			}
+		}
+		w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
+					(force_subclients[2] & 0x07) |
+					((force_subclients[3] & 0x07) << 4));
+	}
+
+	val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
+	if (!(val & 0x08))
+		data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+	if (!(val & 0x80)) {
+		if ((data->lm75[0] != NULL) &&
+			((val & 0x7) == ((val >> 4) & 0x7))) {
+			dev_err(&new_client->dev,
+				"duplicate addresses 0x%x, use force_subclient\n",
+				data->lm75[0]->addr);
+			err = -ENODEV;
+			goto ERROR_SC_1;
+		}
+		data->lm75[1] = i2c_new_dummy(adapter,
+					      0x48 + ((val >> 4) & 0x7));
+	}
+
+	return 0;
+
+/* Undo inits in case of errors */
+
+ERROR_SC_1:
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+ERROR_SC_0:
+	return err;
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+			show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+			show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+			show_temp1, store_temp1, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23,
+			store_temp23, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23,
+			store_temp23, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp1, store_temp1, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 0, 4);
+static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
+			show_temp23, store_temp23, 1, 4);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
+static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
+			show_chassis_clear, store_chassis_clear);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4);
+static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 5);
+static SENSOR_DEVICE_ATTR(pwm7, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 6);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 3);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 2);
+static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 3);
+static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 4);
+static SENSOR_DEVICE_ATTR(pwm6_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 5);
+static SENSOR_DEVICE_ATTR(pwm7_mode, S_IWUSR | S_IRUGO,
+			show_pwm_mode, store_pwm_mode, 6);
+static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO,
+			show_tolerance, store_tolerance, 1);
+static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO,
+			show_tolerance, store_tolerance, 2);
+static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO,
+			show_tolerance, store_tolerance, 3);
+static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
+			show_thermal_cruise, store_thermal_cruise, 1);
+static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
+			show_thermal_cruise, store_thermal_cruise, 2);
+static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
+			show_thermal_cruise, store_thermal_cruise, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 4, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 4, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 3, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_point, store_sf2_point, 4, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
+			show_sf2_level, store_sf2_level, 3, 3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
+			show_fan_min, store_fan_min, 7);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 2);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 3);
+static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 4);
+static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 5);
+static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 6);
+static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
+			show_fan_div, store_fan_div, 7);
+
+static struct attribute *w83792d_attributes_fan[4][7] = {
+	{
+		&sensor_dev_attr_fan4_input.dev_attr.attr,
+		&sensor_dev_attr_fan4_min.dev_attr.attr,
+		&sensor_dev_attr_fan4_div.dev_attr.attr,
+		&sensor_dev_attr_fan4_alarm.dev_attr.attr,
+		&sensor_dev_attr_pwm4.dev_attr.attr,
+		&sensor_dev_attr_pwm4_mode.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan5_input.dev_attr.attr,
+		&sensor_dev_attr_fan5_min.dev_attr.attr,
+		&sensor_dev_attr_fan5_div.dev_attr.attr,
+		&sensor_dev_attr_fan5_alarm.dev_attr.attr,
+		&sensor_dev_attr_pwm5.dev_attr.attr,
+		&sensor_dev_attr_pwm5_mode.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan6_input.dev_attr.attr,
+		&sensor_dev_attr_fan6_min.dev_attr.attr,
+		&sensor_dev_attr_fan6_div.dev_attr.attr,
+		&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+		&sensor_dev_attr_pwm6.dev_attr.attr,
+		&sensor_dev_attr_pwm6_mode.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_fan7_input.dev_attr.attr,
+		&sensor_dev_attr_fan7_min.dev_attr.attr,
+		&sensor_dev_attr_fan7_div.dev_attr.attr,
+		&sensor_dev_attr_fan7_alarm.dev_attr.attr,
+		&sensor_dev_attr_pwm7.dev_attr.attr,
+		&sensor_dev_attr_pwm7_mode.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group w83792d_group_fan[4] = {
+	{ .attrs = w83792d_attributes_fan[0] },
+	{ .attrs = w83792d_attributes_fan[1] },
+	{ .attrs = w83792d_attributes_fan[2] },
+	{ .attrs = w83792d_attributes_fan[3] },
+};
+
+static struct attribute *w83792d_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in8_max.dev_attr.attr,
+	&sensor_dev_attr_in8_min.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	&sensor_dev_attr_in5_alarm.dev_attr.attr,
+	&sensor_dev_attr_in6_alarm.dev_attr.attr,
+	&sensor_dev_attr_in7_alarm.dev_attr.attr,
+	&sensor_dev_attr_in8_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_mode.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&dev_attr_alarms.attr,
+	&dev_attr_intrusion0_alarm.attr,
+	&sensor_dev_attr_tolerance1.dev_attr.attr,
+	&sensor_dev_attr_thermal_cruise1.dev_attr.attr,
+	&sensor_dev_attr_tolerance2.dev_attr.attr,
+	&sensor_dev_attr_thermal_cruise2.dev_attr.attr,
+	&sensor_dev_attr_tolerance3.dev_attr.attr,
+	&sensor_dev_attr_thermal_cruise3.dev_attr.attr,
+	&sensor_dev_attr_sf2_point1_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_point2_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_point3_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_point4_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_point1_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_point2_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_point3_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_point4_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_point1_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_point2_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_point3_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_point4_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_level1_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_level2_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_level3_fan1.dev_attr.attr,
+	&sensor_dev_attr_sf2_level1_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_level2_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_level3_fan2.dev_attr.attr,
+	&sensor_dev_attr_sf2_level1_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_level2_fan3.dev_attr.attr,
+	&sensor_dev_attr_sf2_level3_fan3.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_div.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group w83792d_group = {
+	.attrs = w83792d_attributes,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int
+w83792d_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int val1, val2;
+	unsigned short address = client->addr;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80)
+		return -ENODEV;
+
+	val1 = w83792d_read_value(client, W83792D_REG_BANK);
+	val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
+	/* Check for Winbond ID if in bank 0 */
+	if (!(val1 & 0x07)) {  /* is Bank0 */
+		if ((!(val1 & 0x80) && val2 != 0xa3) ||
+		    ((val1 & 0x80) && val2 != 0x5c))
+			return -ENODEV;
+	}
+	/*
+	 * If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
+	 * should match
+	 */
+	if (w83792d_read_value(client, W83792D_REG_I2C_ADDR) != address)
+		return -ENODEV;
+
+	/*  Put it now into bank 0 and Vendor ID High Byte */
+	w83792d_write_value(client,
+			    W83792D_REG_BANK,
+			    (w83792d_read_value(client,
+				W83792D_REG_BANK) & 0x78) | 0x80);
+
+	/* Determine the chip type. */
+	val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
+	val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
+	if (val1 != 0x7a || val2 != 0x5c)
+		return -ENODEV;
+
+	strlcpy(info->type, "w83792d", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int
+w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct w83792d_data *data;
+	struct device *dev = &client->dev;
+	int i, val1, err;
+
+	data = devm_kzalloc(dev, sizeof(struct w83792d_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	err = w83792d_detect_subclients(client);
+	if (err)
+		return err;
+
+	/* Initialize the chip */
+	w83792d_init_client(client);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 7; i++) {
+		data->fan_min[i] = w83792d_read_value(client,
+					W83792D_REG_FAN_MIN[i]);
+	}
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&dev->kobj, &w83792d_group);
+	if (err)
+		goto exit_i2c_unregister;
+
+	/*
+	 * Read GPIO enable register to check if pins for fan 4,5 are used as
+	 * GPIO
+	 */
+	val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
+
+	if (!(val1 & 0x40)) {
+		err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[0]);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	if (!(val1 & 0x20)) {
+		err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[1]);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	val1 = w83792d_read_value(client, W83792D_REG_PIN);
+	if (val1 & 0x40) {
+		err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[2]);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	if (val1 & 0x04) {
+		err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[3]);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	data->hwmon_dev = hwmon_device_register(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(&dev->kobj, &w83792d_group);
+	for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+		sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
+exit_i2c_unregister:
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+	return err;
+}
+
+static int
+w83792d_remove(struct i2c_client *client)
+{
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	int i;
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &w83792d_group);
+	for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+		sysfs_remove_group(&client->dev.kobj,
+				   &w83792d_group_fan[i]);
+
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+
+	return 0;
+}
+
+static void
+w83792d_init_client(struct i2c_client *client)
+{
+	u8 temp2_cfg, temp3_cfg, vid_in_b;
+
+	if (init)
+		w83792d_write_value(client, W83792D_REG_CONFIG, 0x80);
+
+	/*
+	 * Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0):
+	 * W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of
+	 * vin0/vin1 can be modified by user;
+	 * W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of
+	 * vin0/vin1 auto-updated, can NOT be modified by user.
+	 */
+	vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B);
+	w83792d_write_value(client, W83792D_REG_VID_IN_B,
+			    vid_in_b & 0xbf);
+
+	temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP2_CONFIG);
+	temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP3_CONFIG);
+	w83792d_write_value(client, W83792D_REG_TEMP2_CONFIG,
+				temp2_cfg & 0xe6);
+	w83792d_write_value(client, W83792D_REG_TEMP3_CONFIG,
+				temp3_cfg & 0xe6);
+
+	/* Start monitoring */
+	w83792d_write_value(client, W83792D_REG_CONFIG,
+			    (w83792d_read_value(client,
+						W83792D_REG_CONFIG) & 0xf7)
+			    | 0x01);
+}
+
+static struct w83792d_data *w83792d_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83792d_data *data = i2c_get_clientdata(client);
+	int i, j;
+	u8 reg_array_tmp[4], reg_tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after
+	    (jiffies - data->last_updated, (unsigned long) (HZ * 3))
+	    || time_before(jiffies, data->last_updated) || !data->valid) {
+		dev_dbg(dev, "Starting device update\n");
+
+		/* Update the voltages measured value and limits */
+		for (i = 0; i < 9; i++) {
+			data->in[i] = w83792d_read_value(client,
+						W83792D_REG_IN[i]);
+			data->in_max[i] = w83792d_read_value(client,
+						W83792D_REG_IN_MAX[i]);
+			data->in_min[i] = w83792d_read_value(client,
+						W83792D_REG_IN_MIN[i]);
+		}
+		data->low_bits = w83792d_read_value(client,
+						W83792D_REG_LOW_BITS1) +
+				 (w83792d_read_value(client,
+						W83792D_REG_LOW_BITS2) << 8);
+		for (i = 0; i < 7; i++) {
+			/* Update the Fan measured value and limits */
+			data->fan[i] = w83792d_read_value(client,
+						W83792D_REG_FAN[i]);
+			data->fan_min[i] = w83792d_read_value(client,
+						W83792D_REG_FAN_MIN[i]);
+			/* Update the PWM/DC Value and PWM/DC flag */
+			data->pwm[i] = w83792d_read_value(client,
+						W83792D_REG_PWM[i]);
+		}
+
+		reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
+		data->pwmenable[0] = reg_tmp & 0x03;
+		data->pwmenable[1] = (reg_tmp>>2) & 0x03;
+		data->pwmenable[2] = (reg_tmp>>4) & 0x03;
+
+		for (i = 0; i < 3; i++) {
+			data->temp1[i] = w83792d_read_value(client,
+							W83792D_REG_TEMP1[i]);
+		}
+		for (i = 0; i < 2; i++) {
+			for (j = 0; j < 6; j++) {
+				data->temp_add[i][j] = w83792d_read_value(
+					client, W83792D_REG_TEMP_ADD[i][j]);
+			}
+		}
+
+		/* Update the Fan Divisor */
+		for (i = 0; i < 4; i++) {
+			reg_array_tmp[i] = w83792d_read_value(client,
+							W83792D_REG_FAN_DIV[i]);
+		}
+		data->fan_div[0] = reg_array_tmp[0] & 0x07;
+		data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07;
+		data->fan_div[2] = reg_array_tmp[1] & 0x07;
+		data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07;
+		data->fan_div[4] = reg_array_tmp[2] & 0x07;
+		data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07;
+		data->fan_div[6] = reg_array_tmp[3] & 0x07;
+
+		/* Update the realtime status */
+		data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) +
+			(w83792d_read_value(client, W83792D_REG_ALARM2) << 8) +
+			(w83792d_read_value(client, W83792D_REG_ALARM3) << 16);
+
+		/* Update CaseOpen status and it's CLR_CHS. */
+		data->chassis = (w83792d_read_value(client,
+			W83792D_REG_CHASSIS) >> 5) & 0x01;
+
+		/* Update Thermal Cruise/Smart Fan I target value */
+		for (i = 0; i < 3; i++) {
+			data->thermal_cruise[i] =
+				w83792d_read_value(client,
+				W83792D_REG_THERMAL[i]) & 0x7f;
+		}
+
+		/* Update Smart Fan I/II tolerance */
+		reg_tmp = w83792d_read_value(client, W83792D_REG_TOLERANCE[0]);
+		data->tolerance[0] = reg_tmp & 0x0f;
+		data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+		data->tolerance[2] = w83792d_read_value(client,
+					W83792D_REG_TOLERANCE[2]) & 0x0f;
+
+		/* Update Smart Fan II temperature points */
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 4; j++) {
+				data->sf2_points[i][j]
+				  = w83792d_read_value(client,
+					W83792D_REG_POINTS[i][j]) & 0x7f;
+			}
+		}
+
+		/* Update Smart Fan II duty cycle levels */
+		for (i = 0; i < 3; i++) {
+			reg_tmp = w83792d_read_value(client,
+						W83792D_REG_LEVELS[i][0]);
+			data->sf2_levels[i][0] = reg_tmp & 0x0f;
+			data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f;
+			reg_tmp = w83792d_read_value(client,
+						W83792D_REG_LEVELS[i][2]);
+			data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f;
+			data->sf2_levels[i][3] = reg_tmp & 0x0f;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+#ifdef DEBUG
+	w83792d_print_debug(data, dev);
+#endif
+
+	return data;
+}
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
+{
+	int i = 0, j = 0;
+	dev_dbg(dev, "==========The following is the debug message...========\n");
+	dev_dbg(dev, "9 set of Voltages: =====>\n");
+	for (i = 0; i < 9; i++) {
+		dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]);
+		dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]);
+		dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]);
+	}
+	dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits & 0xff);
+	dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits >> 8);
+	dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n");
+	for (i = 0; i < 7; i++) {
+		dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
+		dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
+		dev_dbg(dev, "pwm[%d]     is: 0x%x\n", i, data->pwm[i]);
+	}
+	dev_dbg(dev, "3 set of Temperatures: =====>\n");
+	for (i = 0; i < 3; i++)
+		dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]);
+
+	for (i = 0; i < 2; i++) {
+		for (j = 0; j < 6; j++) {
+			dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j,
+							data->temp_add[i][j]);
+		}
+	}
+
+	for (i = 0; i < 7; i++)
+		dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]);
+
+	dev_dbg(dev, "==========End of the debug message...================\n");
+	dev_dbg(dev, "\n");
+}
+#endif
+
+module_i2c_driver(w83792d_driver);
+
+MODULE_AUTHOR("Shane Huang (Winbond)");
+MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
new file mode 100644
index 0000000..816aa6c
--- /dev/null
+++ b/drivers/hwmon/w83793.c
@@ -0,0 +1,2181 @@
+/*
+ * w83793.c - Linux kernel driver for hardware monitoring
+ * Copyright (C) 2006 Winbond Electronics Corp.
+ *	      Yuan Mu
+ *	      Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG.
+ *		Watchdog driver part
+ *		(Based partially on fschmd driver,
+ *		 Copyright 2007-2008 by Hans de Goede)
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * w83793	10	12	8	6	0x7b	0x5ca3	yes	no
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/jiffies.h>
+
+/* Default values */
+#define WATCHDOG_TIMEOUT 2	/* 2 minute default timeout */
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+						I2C_CLIENT_END };
+
+/* Insmod parameters */
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients,
+		 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static bool reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+static int timeout = WATCHDOG_TIMEOUT;	/* default timeout in minutes */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+	"Watchdog timeout in minutes. 2<= timeout <=255 (default="
+				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved
+ * as ID, Bank Select registers
+ */
+#define W83793_REG_BANKSEL		0x00
+#define W83793_REG_VENDORID		0x0d
+#define W83793_REG_CHIPID		0x0e
+#define W83793_REG_DEVICEID		0x0f
+
+#define W83793_REG_CONFIG		0x40
+#define W83793_REG_MFC			0x58
+#define W83793_REG_FANIN_CTRL		0x5c
+#define W83793_REG_FANIN_SEL		0x5d
+#define W83793_REG_I2C_ADDR		0x0b
+#define W83793_REG_I2C_SUBADDR		0x0c
+#define W83793_REG_VID_INA		0x05
+#define W83793_REG_VID_INB		0x06
+#define W83793_REG_VID_LATCHA		0x07
+#define W83793_REG_VID_LATCHB		0x08
+#define W83793_REG_VID_CTRL		0x59
+
+#define W83793_REG_WDT_LOCK		0x01
+#define W83793_REG_WDT_ENABLE		0x02
+#define W83793_REG_WDT_STATUS		0x03
+#define W83793_REG_WDT_TIMEOUT		0x04
+
+static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f };
+
+#define TEMP_READ	0
+#define TEMP_CRIT	1
+#define TEMP_CRIT_HYST	2
+#define TEMP_WARN	3
+#define TEMP_WARN_HYST	4
+/*
+ * only crit and crit_hyst affect real-time alarm status
+ * current crit crit_hyst warn warn_hyst
+ */
+static u16 W83793_REG_TEMP[][5] = {
+	{0x1c, 0x78, 0x79, 0x7a, 0x7b},
+	{0x1d, 0x7c, 0x7d, 0x7e, 0x7f},
+	{0x1e, 0x80, 0x81, 0x82, 0x83},
+	{0x1f, 0x84, 0x85, 0x86, 0x87},
+	{0x20, 0x88, 0x89, 0x8a, 0x8b},
+	{0x21, 0x8c, 0x8d, 0x8e, 0x8f},
+};
+
+#define W83793_REG_TEMP_LOW_BITS	0x22
+
+#define W83793_REG_BEEP(index)		(0x53 + (index))
+#define W83793_REG_ALARM(index)		(0x4b + (index))
+
+#define W83793_REG_CLR_CHASSIS		0x4a	/* SMI MASK4 */
+#define W83793_REG_IRQ_CTRL		0x50
+#define W83793_REG_OVT_CTRL		0x51
+#define W83793_REG_OVT_BEEP		0x52
+
+#define IN_READ				0
+#define IN_MAX				1
+#define IN_LOW				2
+static const u16 W83793_REG_IN[][3] = {
+	/* Current, High, Low */
+	{0x10, 0x60, 0x61},	/* Vcore A	*/
+	{0x11, 0x62, 0x63},	/* Vcore B	*/
+	{0x12, 0x64, 0x65},	/* Vtt		*/
+	{0x14, 0x6a, 0x6b},	/* VSEN1	*/
+	{0x15, 0x6c, 0x6d},	/* VSEN2	*/
+	{0x16, 0x6e, 0x6f},	/* +3VSEN	*/
+	{0x17, 0x70, 0x71},	/* +12VSEN	*/
+	{0x18, 0x72, 0x73},	/* 5VDD		*/
+	{0x19, 0x74, 0x75},	/* 5VSB		*/
+	{0x1a, 0x76, 0x77},	/* VBAT		*/
+};
+
+/* Low Bits of Vcore A/B Vtt Read/High/Low */
+static const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 };
+static u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 };
+static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 };
+
+#define W83793_REG_FAN(index)		(0x23 + 2 * (index))	/* High byte */
+#define W83793_REG_FAN_MIN(index)	(0x90 + 2 * (index))	/* High byte */
+
+#define W83793_REG_PWM_DEFAULT		0xb2
+#define W83793_REG_PWM_ENABLE		0x207
+#define W83793_REG_PWM_UPTIME		0xc3	/* Unit in 0.1 second */
+#define W83793_REG_PWM_DOWNTIME		0xc4	/* Unit in 0.1 second */
+#define W83793_REG_TEMP_CRITICAL	0xc5
+
+#define PWM_DUTY			0
+#define PWM_START			1
+#define PWM_NONSTOP			2
+#define PWM_STOP_TIME			3
+#define W83793_REG_PWM(index, nr)	(((nr) == 0 ? 0xb3 : \
+					 (nr) == 1 ? 0x220 : 0x218) + (index))
+
+/* bit field, fan1 is bit0, fan2 is bit1 ... */
+#define W83793_REG_TEMP_FAN_MAP(index)	(0x201 + (index))
+#define W83793_REG_TEMP_TOL(index)	(0x208 + (index))
+#define W83793_REG_TEMP_CRUISE(index)	(0x210 + (index))
+#define W83793_REG_PWM_STOP_TIME(index)	(0x228 + (index))
+#define W83793_REG_SF2_TEMP(index, nr)	(0x230 + ((index) << 4) + (nr))
+#define W83793_REG_SF2_PWM(index, nr)	(0x238 + ((index) << 4) + (nr))
+
+static inline unsigned long FAN_FROM_REG(u16 val)
+{
+	if ((val >= 0xfff) || (val == 0))
+		return	0;
+	return 1350000UL / val;
+}
+
+static inline u16 FAN_TO_REG(long rpm)
+{
+	if (rpm <= 0)
+		return 0x0fff;
+	return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+}
+
+static inline unsigned long TIME_FROM_REG(u8 reg)
+{
+	return reg * 100;
+}
+
+static inline u8 TIME_TO_REG(unsigned long val)
+{
+	return clamp_val((val + 50) / 100, 0, 0xff);
+}
+
+static inline long TEMP_FROM_REG(s8 reg)
+{
+	return reg * 1000;
+}
+
+static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
+{
+	return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max);
+}
+
+struct w83793_data {
+	struct i2c_client *lm75[2];
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	unsigned long last_nonvolatile;	/* In jiffies, last time we update the
+					 * nonvolatile registers
+					 */
+
+	u8 bank;
+	u8 vrm;
+	u8 vid[2];
+	u8 in[10][3];		/* Register value, read/high/low */
+	u8 in_low_bits[3];	/* Additional resolution for VCore A/B Vtt */
+
+	u16 has_fan;		/* Only fan1- fan5 has own pins */
+	u16 fan[12];		/* Register value combine */
+	u16 fan_min[12];	/* Register value combine */
+
+	s8 temp[6][5];		/* current, crit, crit_hyst,warn, warn_hyst */
+	u8 temp_low_bits;	/* Additional resolution TD1-TD4 */
+	u8 temp_mode[2];	/* byte 0: Temp D1-D4 mode each has 2 bits
+				 * byte 1: Temp R1,R2 mode, each has 1 bit
+				 */
+	u8 temp_critical;	/* If reached all fan will be at full speed */
+	u8 temp_fan_map[6];	/* Temp controls which pwm fan, bit field */
+
+	u8 has_pwm;
+	u8 has_temp;
+	u8 has_vid;
+	u8 pwm_enable;		/* Register value, each Temp has 1 bit */
+	u8 pwm_uptime;		/* Register value */
+	u8 pwm_downtime;	/* Register value */
+	u8 pwm_default;		/* All fan default pwm, next poweron valid */
+	u8 pwm[8][3];		/* Register value */
+	u8 pwm_stop_time[8];
+	u8 temp_cruise[6];
+
+	u8 alarms[5];		/* realtime status registers */
+	u8 beeps[5];
+	u8 beep_enable;
+	u8 tolerance[3];	/* Temp tolerance(Smart Fan I/II) */
+	u8 sf2_pwm[6][7];	/* Smart FanII: Fan duty cycle */
+	u8 sf2_temp[6][7];	/* Smart FanII: Temp level point */
+
+	/* watchdog */
+	struct i2c_client *client;
+	struct mutex watchdog_lock;
+	struct list_head list; /* member of the watchdog_data_list */
+	struct kref kref;
+	struct miscdevice watchdog_miscdev;
+	unsigned long watchdog_is_open;
+	char watchdog_expect_close;
+	char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
+	unsigned int watchdog_caused_reboot;
+	int watchdog_timeout; /* watchdog timeout in minutes */
+};
+
+/*
+ * Somewhat ugly :( global data pointer list with all devices, so that
+ * we can find our device data as when using misc_register. There is no
+ * other method to get to one's device data from the open file-op and
+ * for usage in the reboot notifier callback.
+ */
+static LIST_HEAD(watchdog_data_list);
+
+/* Note this lock not only protect list access, but also data.kref access */
+static DEFINE_MUTEX(watchdog_data_mutex);
+
+/*
+ * Release our data struct when we're detached from the i2c client *and* all
+ * references to our watchdog device are released
+ */
+static void w83793_release_resources(struct kref *ref)
+{
+	struct w83793_data *data = container_of(ref, struct w83793_data, kref);
+	kfree(data);
+}
+
+static u8 w83793_read_value(struct i2c_client *client, u16 reg);
+static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
+static int w83793_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
+static int w83793_detect(struct i2c_client *client,
+			 struct i2c_board_info *info);
+static int w83793_remove(struct i2c_client *client);
+static void w83793_init_client(struct i2c_client *client);
+static void w83793_update_nonvolatile(struct device *dev);
+static struct w83793_data *w83793_update_device(struct device *dev);
+
+static const struct i2c_device_id w83793_id[] = {
+	{ "w83793", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83793_id);
+
+static struct i2c_driver w83793_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		   .name = "w83793",
+	},
+	.probe		= w83793_probe,
+	.remove		= w83793_remove,
+	.id_table	= w83793_id,
+	.detect		= w83793_detect,
+	.address_list	= normal_i2c,
+};
+
+static ssize_t
+show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83793_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83793_data *data = w83793_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid[index], data->vrm));
+}
+
+static ssize_t
+store_vrm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct w83793_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 255)
+		return -EINVAL;
+
+	data->vrm = val;
+	return count;
+}
+
+#define ALARM_STATUS			0
+#define BEEP_ENABLE			1
+static ssize_t
+show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83793_data *data = w83793_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index >> 3;
+	int bit = sensor_attr->index & 0x07;
+	u8 val;
+
+	if (nr == ALARM_STATUS) {
+		val = (data->alarms[index] >> (bit)) & 1;
+	} else {		/* BEEP_ENABLE */
+		val = (data->beeps[index] >> (bit)) & 1;
+	}
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index >> 3;
+	int shift = sensor_attr->index & 0x07;
+	u8 beep_bit = 1 << shift;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beeps[index] = w83793_read_value(client, W83793_REG_BEEP(index));
+	data->beeps[index] &= ~beep_bit;
+	data->beeps[index] |= val << shift;
+	w83793_write_value(client, W83793_REG_BEEP(index), data->beeps[index]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83793_data *data = w83793_update_device(dev);
+	return sprintf(buf, "%u\n", (data->beep_enable >> 1) & 0x01);
+}
+
+static ssize_t
+store_beep_enable(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP)
+			    & 0xfd;
+	data->beep_enable |= val << 1;
+	w83793_write_value(client, W83793_REG_OVT_BEEP, data->beep_enable);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* Write 0 to clear chassis alarm */
+static ssize_t
+store_chassis_clear(struct device *dev,
+		    struct device_attribute *attr, const char *buf,
+		    size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	u8 reg;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
+	w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80);
+	data->valid = 0;		/* Force cache refresh */
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define FAN_INPUT			0
+#define FAN_MIN				1
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+	u16 val;
+
+	if (nr == FAN_INPUT)
+		val = data->fan[index] & 0x0fff;
+	else
+		val = data->fan_min[index] & 0x0fff;
+
+	return sprintf(buf, "%lu\n", FAN_FROM_REG(val));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = FAN_TO_REG(val);
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[index] = val;
+	w83793_write_value(client, W83793_REG_FAN_MIN(index),
+			   (val >> 8) & 0xff);
+	w83793_write_value(client, W83793_REG_FAN_MIN(index) + 1, val & 0xff);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	struct w83793_data *data = w83793_update_device(dev);
+	u16 val;
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+
+	if (nr == PWM_STOP_TIME)
+		val = TIME_FROM_REG(data->pwm_stop_time[index]);
+	else
+		val = (data->pwm[index][nr] & 0x3f) << 2;
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (nr == PWM_STOP_TIME) {
+		val = TIME_TO_REG(val);
+		data->pwm_stop_time[index] = val;
+		w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index),
+				   val);
+	} else {
+		val = clamp_val(val, 0, 0xff) >> 2;
+		data->pwm[index][nr] =
+		    w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0;
+		data->pwm[index][nr] |= val;
+		w83793_write_value(client, W83793_REG_PWM(index, nr),
+							data->pwm[index][nr]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+	long temp = TEMP_FROM_REG(data->temp[index][nr]);
+
+	if (nr == TEMP_READ && index < 4) {	/* Only TD1-TD4 have low bits */
+		int low = ((data->temp_low_bits >> (index * 2)) & 0x03) * 250;
+		temp += temp > 0 ? low : -low;
+	}
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	long tmp;
+	int err;
+
+	err = kstrtol(buf, 10, &tmp);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127);
+	w83793_write_value(client, W83793_REG_TEMP[index][nr],
+			   data->temp[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * TD1-TD4
+ * each has 4 mode:(2 bits)
+ * 0:	Stop monitor
+ * 1:	Use internal temp sensor(default)
+ * 2:	Reserved
+ * 3:	Use sensor in Intel CPU and get result by PECI
+ *
+ * TR1-TR2
+ * each has 2 mode:(1 bit)
+ * 0:	Disable temp sensor monitor
+ * 1:	To enable temp sensors monitor
+ */
+
+/* 0 disable, 6 PECI */
+static u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 };
+
+static ssize_t
+show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83793_data *data = w83793_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	u8 mask = (index < 4) ? 0x03 : 0x01;
+	u8 shift = (index < 4) ? (2 * index) : (index - 4);
+	u8 tmp;
+	index = (index < 4) ? 0 : 1;
+
+	tmp = (data->temp_mode[index] >> shift) & mask;
+
+	/* for the internal sensor, found out if diode or thermistor */
+	if (tmp == 1)
+		tmp = index == 0 ? 3 : 4;
+	else
+		tmp = TO_TEMP_MODE[tmp];
+
+	return sprintf(buf, "%d\n", tmp);
+}
+
+static ssize_t
+store_temp_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	u8 mask = (index < 4) ? 0x03 : 0x01;
+	u8 shift = (index < 4) ? (2 * index) : (index - 4);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/* transform the sysfs interface values into table above */
+	if ((val == 6) && (index < 4)) {
+		val -= 3;
+	} else if ((val == 3 && index < 4)
+		|| (val == 4 && index >= 4)) {
+		/* transform diode or thermistor into internal enable */
+		val = !!val;
+	} else {
+		return -EINVAL;
+	}
+
+	index = (index < 4) ? 0 : 1;
+	mutex_lock(&data->update_lock);
+	data->temp_mode[index] =
+	    w83793_read_value(client, W83793_REG_TEMP_MODE[index]);
+	data->temp_mode[index] &= ~(mask << shift);
+	data->temp_mode[index] |= val << shift;
+	w83793_write_value(client, W83793_REG_TEMP_MODE[index],
+							data->temp_mode[index]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define SETUP_PWM_DEFAULT		0
+#define SETUP_PWM_UPTIME		1	/* Unit in 0.1s */
+#define SETUP_PWM_DOWNTIME		2	/* Unit in 0.1s */
+#define SETUP_TEMP_CRITICAL		3
+static ssize_t
+show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct w83793_data *data = w83793_update_device(dev);
+	u32 val = 0;
+
+	if (nr == SETUP_PWM_DEFAULT)
+		val = (data->pwm_default & 0x3f) << 2;
+	else if (nr == SETUP_PWM_UPTIME)
+		val = TIME_FROM_REG(data->pwm_uptime);
+	else if (nr == SETUP_PWM_DOWNTIME)
+		val = TIME_FROM_REG(data->pwm_downtime);
+	else if (nr == SETUP_TEMP_CRITICAL)
+		val = TEMP_FROM_REG(data->temp_critical & 0x7f);
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_setup(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (nr == SETUP_PWM_DEFAULT) {
+		data->pwm_default =
+		    w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0;
+		data->pwm_default |= clamp_val(val, 0, 0xff) >> 2;
+		w83793_write_value(client, W83793_REG_PWM_DEFAULT,
+							data->pwm_default);
+	} else if (nr == SETUP_PWM_UPTIME) {
+		data->pwm_uptime = TIME_TO_REG(val);
+		data->pwm_uptime += data->pwm_uptime == 0 ? 1 : 0;
+		w83793_write_value(client, W83793_REG_PWM_UPTIME,
+							data->pwm_uptime);
+	} else if (nr == SETUP_PWM_DOWNTIME) {
+		data->pwm_downtime = TIME_TO_REG(val);
+		data->pwm_downtime += data->pwm_downtime == 0 ? 1 : 0;
+		w83793_write_value(client, W83793_REG_PWM_DOWNTIME,
+							data->pwm_downtime);
+	} else {		/* SETUP_TEMP_CRITICAL */
+		data->temp_critical =
+		    w83793_read_value(client, W83793_REG_TEMP_CRITICAL) & 0x80;
+		data->temp_critical |= TEMP_TO_REG(val, 0, 0x7f);
+		w83793_write_value(client, W83793_REG_TEMP_CRITICAL,
+							data->temp_critical);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/*
+ * Temp SmartFan control
+ * TEMP_FAN_MAP
+ * Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1...
+ * It's possible two or more temp channels control the same fan, w83793
+ * always prefers to pick the most critical request and applies it to
+ * the related Fan.
+ * It's possible one fan is not in any mapping of 6 temp channels, this
+ * means the fan is manual mode
+ *
+ * TEMP_PWM_ENABLE
+ * Each temp channel has its own SmartFan mode, and temp channel
+ * control fans that are set by TEMP_FAN_MAP
+ * 0:	SmartFanII mode
+ * 1:	Thermal Cruise Mode
+ *
+ * TEMP_CRUISE
+ * Target temperature in thermal cruise mode, w83793 will try to turn
+ * fan speed to keep the temperature of target device around this
+ * temperature.
+ *
+ * TEMP_TOLERANCE
+ * If Temp higher or lower than target with this tolerance, w83793
+ * will take actions to speed up or slow down the fan to keep the
+ * temperature within the tolerance range.
+ */
+
+#define TEMP_FAN_MAP			0
+#define TEMP_PWM_ENABLE			1
+#define TEMP_CRUISE			2
+#define TEMP_TOLERANCE			3
+static ssize_t
+show_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+	u32 val;
+
+	if (nr == TEMP_FAN_MAP) {
+		val = data->temp_fan_map[index];
+	} else if (nr == TEMP_PWM_ENABLE) {
+		/* +2 to transform into 2 and 3 to conform with sysfs intf */
+		val = ((data->pwm_enable >> index) & 0x01) + 2;
+	} else if (nr == TEMP_CRUISE) {
+		val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f);
+	} else {		/* TEMP_TOLERANCE */
+		val = data->tolerance[index >> 1] >> ((index & 0x01) ? 4 : 0);
+		val = TEMP_FROM_REG(val & 0x0f);
+	}
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_ctrl(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	if (nr == TEMP_FAN_MAP) {
+		val = clamp_val(val, 0, 255);
+		w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val);
+		data->temp_fan_map[index] = val;
+	} else if (nr == TEMP_PWM_ENABLE) {
+		if (val == 2 || val == 3) {
+			data->pwm_enable =
+			    w83793_read_value(client, W83793_REG_PWM_ENABLE);
+			if (val - 2)
+				data->pwm_enable |= 1 << index;
+			else
+				data->pwm_enable &= ~(1 << index);
+			w83793_write_value(client, W83793_REG_PWM_ENABLE,
+							data->pwm_enable);
+		} else {
+			mutex_unlock(&data->update_lock);
+			return -EINVAL;
+		}
+	} else if (nr == TEMP_CRUISE) {
+		data->temp_cruise[index] =
+		    w83793_read_value(client, W83793_REG_TEMP_CRUISE(index));
+		data->temp_cruise[index] &= 0x80;
+		data->temp_cruise[index] |= TEMP_TO_REG(val, 0, 0x7f);
+
+		w83793_write_value(client, W83793_REG_TEMP_CRUISE(index),
+						data->temp_cruise[index]);
+	} else {		/* TEMP_TOLERANCE */
+		int i = index >> 1;
+		u8 shift = (index & 0x01) ? 4 : 0;
+		data->tolerance[i] =
+		    w83793_read_value(client, W83793_REG_TEMP_TOL(i));
+
+		data->tolerance[i] &= ~(0x0f << shift);
+		data->tolerance[i] |= TEMP_TO_REG(val, 0, 0x0f) << shift;
+		w83793_write_value(client, W83793_REG_TEMP_TOL(i),
+							data->tolerance[i]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_sf2_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+
+	return sprintf(buf, "%d\n", (data->sf2_pwm[index][nr] & 0x3f) << 2);
+}
+
+static ssize_t
+store_sf2_pwm(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = clamp_val(val, 0, 0xff) >> 2;
+
+	mutex_lock(&data->update_lock);
+	data->sf2_pwm[index][nr] =
+	    w83793_read_value(client, W83793_REG_SF2_PWM(index, nr)) & 0xc0;
+	data->sf2_pwm[index][nr] |= val;
+	w83793_write_value(client, W83793_REG_SF2_PWM(index, nr),
+						data->sf2_pwm[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_sf2_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+
+	return sprintf(buf, "%ld\n",
+		       TEMP_FROM_REG(data->sf2_temp[index][nr] & 0x7f));
+}
+
+static ssize_t
+store_sf2_temp(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+	val = TEMP_TO_REG(val, 0, 0x7f);
+
+	mutex_lock(&data->update_lock);
+	data->sf2_temp[index][nr] =
+	    w83793_read_value(client, W83793_REG_SF2_TEMP(index, nr)) & 0x80;
+	data->sf2_temp[index][nr] |= val;
+	w83793_write_value(client, W83793_REG_SF2_TEMP(index, nr),
+					     data->sf2_temp[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* only Vcore A/B and Vtt have additional 2 bits precision */
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83793_data *data = w83793_update_device(dev);
+	u16 val = data->in[index][nr];
+
+	if (index < 3) {
+		val <<= 2;
+		val += (data->in_low_bits[nr] >> (index * 2)) & 0x3;
+	}
+	/* voltage inputs 5VDD and 5VSB needs 150mV offset */
+	val = val * scale_in[index] + scale_in_add[index];
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_in(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = (val + scale_in[index] / 2) / scale_in[index];
+
+	mutex_lock(&data->update_lock);
+	if (index > 2) {
+		/* fix the limit values of 5VDD and 5VSB to ALARM mechanism */
+		if (nr == 1 || nr == 2)
+			val -= scale_in_add[index] / scale_in[index];
+		val = clamp_val(val, 0, 255);
+	} else {
+		val = clamp_val(val, 0, 0x3FF);
+		data->in_low_bits[nr] =
+		    w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]);
+		data->in_low_bits[nr] &= ~(0x03 << (2 * index));
+		data->in_low_bits[nr] |= (val & 0x03) << (2 * index);
+		w83793_write_value(client, W83793_REG_IN_LOW_BITS[nr],
+						     data->in_low_bits[nr]);
+		val >>= 2;
+	}
+	data->in[index][nr] = val;
+	w83793_write_value(client, W83793_REG_IN[index][nr],
+							data->in[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define NOT_USED			-1
+
+#define SENSOR_ATTR_IN(index)						\
+	SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,	\
+		IN_READ, index),					\
+	SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_MAX, index),				\
+	SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_LOW, index),				\
+	SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + ((index > 2) ? 1 : 0)),	\
+	SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE,		\
+		index + ((index > 2) ? 1 : 0))
+
+#define SENSOR_ATTR_FAN(index)						\
+	SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + 17),			\
+	SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 17),	\
+	SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,		\
+		NULL, FAN_INPUT, index - 1),				\
+	SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO,		\
+		show_fan, store_fan_min, FAN_MIN, index - 1)
+
+#define SENSOR_ATTR_PWM(index)						\
+	SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,		\
+		store_pwm, PWM_DUTY, index - 1),			\
+	SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_NONSTOP, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_START, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,	\
+		show_pwm, store_pwm, PWM_STOP_TIME, index - 1)
+
+#define SENSOR_ATTR_TEMP(index)						\
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR,		\
+		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp,		\
+		NULL, TEMP_READ, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_CRIT, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_CRIT_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_WARN, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_WARN_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
+		show_alarm_beep, NULL, ALARM_STATUS, index + 11),	\
+	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 11),	\
+	SENSOR_ATTR_2(temp##index##_auto_channels_pwm,			\
+		S_IRUGO | S_IWUSR, show_sf_ctrl, store_sf_ctrl,		\
+		TEMP_FAN_MAP, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO,	\
+		show_sf_ctrl, store_sf_ctrl, TEMP_PWM_ENABLE,		\
+		index - 1),						\
+	SENSOR_ATTR_2(thermal_cruise##index, S_IRUGO | S_IWUSR,		\
+		show_sf_ctrl, store_sf_ctrl, TEMP_CRUISE, index - 1),	\
+	SENSOR_ATTR_2(tolerance##index, S_IRUGO | S_IWUSR, show_sf_ctrl,\
+		store_sf_ctrl, TEMP_TOLERANCE, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
+		show_sf2_pwm, store_sf2_pwm, 6, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
+		show_sf2_temp, store_sf2_temp, 6, index - 1)
+
+static struct sensor_device_attribute_2 w83793_sensor_attr_2[] = {
+	SENSOR_ATTR_IN(0),
+	SENSOR_ATTR_IN(1),
+	SENSOR_ATTR_IN(2),
+	SENSOR_ATTR_IN(3),
+	SENSOR_ATTR_IN(4),
+	SENSOR_ATTR_IN(5),
+	SENSOR_ATTR_IN(6),
+	SENSOR_ATTR_IN(7),
+	SENSOR_ATTR_IN(8),
+	SENSOR_ATTR_IN(9),
+	SENSOR_ATTR_FAN(1),
+	SENSOR_ATTR_FAN(2),
+	SENSOR_ATTR_FAN(3),
+	SENSOR_ATTR_FAN(4),
+	SENSOR_ATTR_FAN(5),
+	SENSOR_ATTR_PWM(1),
+	SENSOR_ATTR_PWM(2),
+	SENSOR_ATTR_PWM(3),
+};
+
+static struct sensor_device_attribute_2 w83793_temp[] = {
+	SENSOR_ATTR_TEMP(1),
+	SENSOR_ATTR_TEMP(2),
+	SENSOR_ATTR_TEMP(3),
+	SENSOR_ATTR_TEMP(4),
+	SENSOR_ATTR_TEMP(5),
+	SENSOR_ATTR_TEMP(6),
+};
+
+/* Fan6-Fan12 */
+static struct sensor_device_attribute_2 w83793_left_fan[] = {
+	SENSOR_ATTR_FAN(6),
+	SENSOR_ATTR_FAN(7),
+	SENSOR_ATTR_FAN(8),
+	SENSOR_ATTR_FAN(9),
+	SENSOR_ATTR_FAN(10),
+	SENSOR_ATTR_FAN(11),
+	SENSOR_ATTR_FAN(12),
+};
+
+/* Pwm4-Pwm8 */
+static struct sensor_device_attribute_2 w83793_left_pwm[] = {
+	SENSOR_ATTR_PWM(4),
+	SENSOR_ATTR_PWM(5),
+	SENSOR_ATTR_PWM(6),
+	SENSOR_ATTR_PWM(7),
+	SENSOR_ATTR_PWM(8),
+};
+
+static struct sensor_device_attribute_2 w83793_vid[] = {
+	SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
+	SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
+};
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
+
+static struct sensor_device_attribute_2 sda_single_files[] = {
+	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_chassis_clear, ALARM_STATUS, 30),
+	SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
+		      store_beep_enable, NOT_USED, NOT_USED),
+	SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
+	SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
+	SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
+	SENSOR_ATTR_2(temp_critical, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_TEMP_CRITICAL, NOT_USED),
+};
+
+static void w83793_init_client(struct i2c_client *client)
+{
+	if (reset)
+		w83793_write_value(client, W83793_REG_CONFIG, 0x80);
+
+	/* Start monitoring */
+	w83793_write_value(client, W83793_REG_CONFIG,
+			   w83793_read_value(client, W83793_REG_CONFIG) | 0x01);
+}
+
+/*
+ * Watchdog routines
+ */
+
+static int watchdog_set_timeout(struct w83793_data *data, int timeout)
+{
+	unsigned int mtimeout;
+	int ret;
+
+	mtimeout = DIV_ROUND_UP(timeout, 60);
+
+	if (mtimeout > 255)
+		return -EINVAL;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	data->watchdog_timeout = mtimeout;
+
+	/* Set Timeout value (in Minutes) */
+	w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+			   data->watchdog_timeout);
+
+	ret = mtimeout * 60;
+
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_get_timeout(struct w83793_data *data)
+{
+	int timeout;
+
+	mutex_lock(&data->watchdog_lock);
+	timeout = data->watchdog_timeout * 60;
+	mutex_unlock(&data->watchdog_lock);
+
+	return timeout;
+}
+
+static int watchdog_trigger(struct w83793_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	/* Set Timeout value (in Minutes) */
+	w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+			   data->watchdog_timeout);
+
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_enable(struct w83793_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	/* Set initial timeout */
+	w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+			   data->watchdog_timeout);
+
+	/* Enable Soft Watchdog */
+	w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0x55);
+
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_disable(struct w83793_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->watchdog_lock);
+	if (!data->client) {
+		ret = -ENODEV;
+		goto leave;
+	}
+
+	/* Disable Soft Watchdog */
+	w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0xAA);
+
+leave:
+	mutex_unlock(&data->watchdog_lock);
+	return ret;
+}
+
+static int watchdog_open(struct inode *inode, struct file *filp)
+{
+	struct w83793_data *pos, *data = NULL;
+	int watchdog_is_open;
+
+	/*
+	 * We get called from drivers/char/misc.c with misc_mtx hold, and we
+	 * call misc_register() from  w83793_probe() with watchdog_data_mutex
+	 * hold, as misc_register() takes the misc_mtx lock, this is a possible
+	 * deadlock, so we use mutex_trylock here.
+	 */
+	if (!mutex_trylock(&watchdog_data_mutex))
+		return -ERESTARTSYS;
+	list_for_each_entry(pos, &watchdog_data_list, list) {
+		if (pos->watchdog_miscdev.minor == iminor(inode)) {
+			data = pos;
+			break;
+		}
+	}
+
+	/* Check, if device is already open */
+	watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
+
+	/*
+	 * Increase data reference counter (if not already done).
+	 * Note we can never not have found data, so we don't check for this
+	 */
+	if (!watchdog_is_open)
+		kref_get(&data->kref);
+
+	mutex_unlock(&watchdog_data_mutex);
+
+	/* Check, if device is already open and possibly issue error */
+	if (watchdog_is_open)
+		return -EBUSY;
+
+	/* Enable Soft Watchdog */
+	watchdog_enable(data);
+
+	/* Store pointer to data into filp's private data */
+	filp->private_data = data;
+
+	return nonseekable_open(inode, filp);
+}
+
+static int watchdog_close(struct inode *inode, struct file *filp)
+{
+	struct w83793_data *data = filp->private_data;
+
+	if (data->watchdog_expect_close) {
+		watchdog_disable(data);
+		data->watchdog_expect_close = 0;
+	} else {
+		watchdog_trigger(data);
+		dev_crit(&data->client->dev,
+			"unexpected close, not stopping watchdog!\n");
+	}
+
+	clear_bit(0, &data->watchdog_is_open);
+
+	/* Decrease data reference counter */
+	mutex_lock(&watchdog_data_mutex);
+	kref_put(&data->kref, w83793_release_resources);
+	mutex_unlock(&watchdog_data_mutex);
+
+	return 0;
+}
+
+static ssize_t watchdog_write(struct file *filp, const char __user *buf,
+	size_t count, loff_t *offset)
+{
+	ssize_t ret;
+	struct w83793_data *data = filp->private_data;
+
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* Clear it in case it was set with a previous write */
+			data->watchdog_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					data->watchdog_expect_close = 1;
+			}
+		}
+		ret = watchdog_trigger(data);
+		if (ret < 0)
+			return ret;
+	}
+	return count;
+}
+
+static long watchdog_ioctl(struct file *filp, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING |
+			   WDIOF_SETTIMEOUT |
+			   WDIOF_CARDRESET,
+		.identity = "w83793 watchdog"
+	};
+
+	int val, ret = 0;
+	struct w83793_data *data = filp->private_data;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (!nowayout)
+			ident.options |= WDIOF_MAGICCLOSE;
+		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
+			ret = -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+		val = data->watchdog_caused_reboot ? WDIOF_CARDRESET : 0;
+		ret = put_user(val, (int __user *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, (int __user *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		ret = watchdog_trigger(data);
+		break;
+
+	case WDIOC_GETTIMEOUT:
+		val = watchdog_get_timeout(data);
+		ret = put_user(val, (int __user *)arg);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(val, (int __user *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = watchdog_set_timeout(data, val);
+		if (ret > 0)
+			ret = put_user(ret, (int __user *)arg);
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(val, (int __user *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (val & WDIOS_DISABLECARD)
+			ret = watchdog_disable(data);
+		else if (val & WDIOS_ENABLECARD)
+			ret = watchdog_enable(data);
+		else
+			ret = -EINVAL;
+
+		break;
+	default:
+		ret = -ENOTTY;
+	}
+	return ret;
+}
+
+static const struct file_operations watchdog_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = watchdog_open,
+	.release = watchdog_close,
+	.write = watchdog_write,
+	.unlocked_ioctl = watchdog_ioctl,
+};
+
+/*
+ *	Notifier for system down
+ */
+
+static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
+			       void *unused)
+{
+	struct w83793_data *data = NULL;
+
+	if (code == SYS_DOWN || code == SYS_HALT) {
+
+		/* Disable each registered watchdog */
+		mutex_lock(&watchdog_data_mutex);
+		list_for_each_entry(data, &watchdog_data_list, list) {
+			if (data->watchdog_miscdev.minor)
+				watchdog_disable(data);
+		}
+		mutex_unlock(&watchdog_data_mutex);
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block watchdog_notifier = {
+	.notifier_call = watchdog_notify_sys,
+};
+
+/*
+ * Init / remove routines
+ */
+
+static int w83793_remove(struct i2c_client *client)
+{
+	struct w83793_data *data = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+	int i, tmp;
+
+	/* Unregister the watchdog (if registered) */
+	if (data->watchdog_miscdev.minor) {
+		misc_deregister(&data->watchdog_miscdev);
+
+		if (data->watchdog_is_open) {
+			dev_warn(&client->dev,
+				"i2c client detached with watchdog open! "
+				"Stopping watchdog.\n");
+			watchdog_disable(data);
+		}
+
+		mutex_lock(&watchdog_data_mutex);
+		list_del(&data->list);
+		mutex_unlock(&watchdog_data_mutex);
+
+		/* Tell the watchdog code the client is gone */
+		mutex_lock(&data->watchdog_lock);
+		data->client = NULL;
+		mutex_unlock(&data->watchdog_lock);
+	}
+
+	/* Reset Configuration Register to Disable Watch Dog Registers */
+	tmp = w83793_read_value(client, W83793_REG_CONFIG);
+	w83793_write_value(client, W83793_REG_CONFIG, tmp & ~0x04);
+
+	unregister_reboot_notifier(&watchdog_notifier);
+
+	hwmon_device_unregister(data->hwmon_dev);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
+		device_remove_file(dev,
+				   &w83793_sensor_attr_2[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
+		device_remove_file(dev, &sda_single_files[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
+		device_remove_file(dev, &w83793_vid[i].dev_attr);
+	device_remove_file(dev, &dev_attr_vrm);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
+		device_remove_file(dev, &w83793_left_fan[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
+		device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
+		device_remove_file(dev, &w83793_temp[i].dev_attr);
+
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+
+	/* Decrease data reference counter */
+	mutex_lock(&watchdog_data_mutex);
+	kref_put(&data->kref, w83793_release_resources);
+	mutex_unlock(&watchdog_data_mutex);
+
+	return 0;
+}
+
+static int
+w83793_detect_subclients(struct i2c_client *client)
+{
+	int i, id, err;
+	int address = client->addr;
+	u8 tmp;
+	struct i2c_adapter *adapter = client->adapter;
+	struct w83793_data *data = i2c_get_clientdata(client);
+
+	id = i2c_adapter_id(adapter);
+	if (force_subclients[0] == id && force_subclients[1] == address) {
+		for (i = 2; i <= 3; i++) {
+			if (force_subclients[i] < 0x48
+			    || force_subclients[i] > 0x4f) {
+				dev_err(&client->dev,
+					"invalid subclient "
+					"address %d; must be 0x48-0x4f\n",
+					force_subclients[i]);
+				err = -EINVAL;
+				goto ERROR_SC_0;
+			}
+		}
+		w83793_write_value(client, W83793_REG_I2C_SUBADDR,
+				   (force_subclients[2] & 0x07) |
+				   ((force_subclients[3] & 0x07) << 4));
+	}
+
+	tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
+	if (!(tmp & 0x08))
+		data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
+	if (!(tmp & 0x80)) {
+		if ((data->lm75[0] != NULL)
+		    && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
+			dev_err(&client->dev,
+				"duplicate addresses 0x%x, "
+				"use force_subclients\n", data->lm75[0]->addr);
+			err = -ENODEV;
+			goto ERROR_SC_1;
+		}
+		data->lm75[1] = i2c_new_dummy(adapter,
+					      0x48 + ((tmp >> 4) & 0x7));
+	}
+
+	return 0;
+
+	/* Undo inits in case of errors */
+
+ERROR_SC_1:
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+ERROR_SC_0:
+	return err;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83793_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	u8 tmp, bank, chip_id;
+	struct i2c_adapter *adapter = client->adapter;
+	unsigned short address = client->addr;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
+
+	tmp = bank & 0x80 ? 0x5c : 0xa3;
+	/* Check Winbond vendor ID */
+	if (tmp != i2c_smbus_read_byte_data(client, W83793_REG_VENDORID)) {
+		pr_debug("w83793: Detection failed at check vendor id\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * If Winbond chip, address of chip and W83793_REG_I2C_ADDR
+	 * should match
+	 */
+	if ((bank & 0x07) == 0
+	 && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
+	    (address << 1)) {
+		pr_debug("w83793: Detection failed at check i2c addr\n");
+		return -ENODEV;
+	}
+
+	/* Determine the chip type now */
+	chip_id = i2c_smbus_read_byte_data(client, W83793_REG_CHIPID);
+	if (chip_id != 0x7b)
+		return -ENODEV;
+
+	strlcpy(info->type, "w83793", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int w83793_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
+	struct w83793_data *data;
+	int i, tmp, val, err;
+	int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
+	int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
+	int files_temp = ARRAY_SIZE(w83793_temp) / 6;
+
+	data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(client, data);
+	data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
+	mutex_init(&data->update_lock);
+	mutex_init(&data->watchdog_lock);
+	INIT_LIST_HEAD(&data->list);
+	kref_init(&data->kref);
+
+	/*
+	 * Store client pointer in our data struct for watchdog usage
+	 * (where the client is found through a data ptr instead of the
+	 * otherway around)
+	 */
+	data->client = client;
+
+	err = w83793_detect_subclients(client);
+	if (err)
+		goto free_mem;
+
+	/* Initialize the chip */
+	w83793_init_client(client);
+
+	/*
+	 * Only fan 1-5 has their own input pins,
+	 * Pwm 1-3 has their own pins
+	 */
+	data->has_fan = 0x1f;
+	data->has_pwm = 0x07;
+	tmp = w83793_read_value(client, W83793_REG_MFC);
+	val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
+
+	/* check the function of pins 49-56 */
+	if (tmp & 0x80) {
+		data->has_vid |= 0x2;	/* has VIDB */
+	} else {
+		data->has_pwm |= 0x18;	/* pwm 4,5 */
+		if (val & 0x01) {	/* fan 6 */
+			data->has_fan |= 0x20;
+			data->has_pwm |= 0x20;
+		}
+		if (val & 0x02) {	/* fan 7 */
+			data->has_fan |= 0x40;
+			data->has_pwm |= 0x40;
+		}
+		if (!(tmp & 0x40) && (val & 0x04)) {	/* fan 8 */
+			data->has_fan |= 0x80;
+			data->has_pwm |= 0x80;
+		}
+	}
+
+	/* check the function of pins 37-40 */
+	if (!(tmp & 0x29))
+		data->has_vid |= 0x1;	/* has VIDA */
+	if (0x08 == (tmp & 0x0c)) {
+		if (val & 0x08)	/* fan 9 */
+			data->has_fan |= 0x100;
+		if (val & 0x10)	/* fan 10 */
+			data->has_fan |= 0x200;
+	}
+	if (0x20 == (tmp & 0x30)) {
+		if (val & 0x20)	/* fan 11 */
+			data->has_fan |= 0x400;
+		if (val & 0x40)	/* fan 12 */
+			data->has_fan |= 0x800;
+	}
+
+	if ((tmp & 0x01) && (val & 0x04)) {	/* fan 8, second location */
+		data->has_fan |= 0x80;
+		data->has_pwm |= 0x80;
+	}
+
+	tmp = w83793_read_value(client, W83793_REG_FANIN_SEL);
+	if ((tmp & 0x01) && (val & 0x08)) {	/* fan 9, second location */
+		data->has_fan |= 0x100;
+	}
+	if ((tmp & 0x02) && (val & 0x10)) {	/* fan 10, second location */
+		data->has_fan |= 0x200;
+	}
+	if ((tmp & 0x04) && (val & 0x20)) {	/* fan 11, second location */
+		data->has_fan |= 0x400;
+	}
+	if ((tmp & 0x08) && (val & 0x40)) {	/* fan 12, second location */
+		data->has_fan |= 0x800;
+	}
+
+	/* check the temp1-6 mode, ignore former AMDSI selected inputs */
+	tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[0]);
+	if (tmp & 0x01)
+		data->has_temp |= 0x01;
+	if (tmp & 0x04)
+		data->has_temp |= 0x02;
+	if (tmp & 0x10)
+		data->has_temp |= 0x04;
+	if (tmp & 0x40)
+		data->has_temp |= 0x08;
+
+	tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[1]);
+	if (tmp & 0x01)
+		data->has_temp |= 0x10;
+	if (tmp & 0x02)
+		data->has_temp |= 0x20;
+
+	/* Register sysfs hooks */
+	for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
+		err = device_create_file(dev,
+					 &w83793_sensor_attr_2[i].dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) {
+		if (!(data->has_vid & (1 << i)))
+			continue;
+		err = device_create_file(dev, &w83793_vid[i].dev_attr);
+		if (err)
+			goto exit_remove;
+	}
+	if (data->has_vid) {
+		data->vrm = vid_which_vrm();
+		err = device_create_file(dev, &dev_attr_vrm);
+		if (err)
+			goto exit_remove;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
+		err = device_create_file(dev, &sda_single_files[i].dev_attr);
+		if (err)
+			goto exit_remove;
+
+	}
+
+	for (i = 0; i < 6; i++) {
+		int j;
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		for (j = 0; j < files_temp; j++) {
+			err = device_create_file(dev,
+						&w83793_temp[(i) * files_temp
+								+ j].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	for (i = 5; i < 12; i++) {
+		int j;
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		for (j = 0; j < files_fan; j++) {
+			err = device_create_file(dev,
+					   &w83793_left_fan[(i - 5) * files_fan
+								+ j].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	for (i = 3; i < 8; i++) {
+		int j;
+		if (!(data->has_pwm & (1 << i)))
+			continue;
+		for (j = 0; j < files_pwm; j++) {
+			err = device_create_file(dev,
+					   &w83793_left_pwm[(i - 3) * files_pwm
+								+ j].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	/* Watchdog initialization */
+
+	/* Register boot notifier */
+	err = register_reboot_notifier(&watchdog_notifier);
+	if (err != 0) {
+		dev_err(&client->dev,
+			"cannot register reboot notifier (err=%d)\n", err);
+		goto exit_devunreg;
+	}
+
+	/*
+	 * Enable Watchdog registers.
+	 * Set Configuration Register to Enable Watch Dog Registers
+	 * (Bit 2) = XXXX, X1XX.
+	 */
+	tmp = w83793_read_value(client, W83793_REG_CONFIG);
+	w83793_write_value(client, W83793_REG_CONFIG, tmp | 0x04);
+
+	/* Set the default watchdog timeout */
+	data->watchdog_timeout = timeout;
+
+	/* Check, if last reboot was caused by watchdog */
+	data->watchdog_caused_reboot =
+	  w83793_read_value(data->client, W83793_REG_WDT_STATUS) & 0x01;
+
+	/* Disable Soft Watchdog during initialiation */
+	watchdog_disable(data);
+
+	/*
+	 * We take the data_mutex lock early so that watchdog_open() cannot
+	 * run when misc_register() has completed, but we've not yet added
+	 * our data to the watchdog_data_list (and set the default timeout)
+	 */
+	mutex_lock(&watchdog_data_mutex);
+	for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
+		/* Register our watchdog part */
+		snprintf(data->watchdog_name, sizeof(data->watchdog_name),
+			"watchdog%c", (i == 0) ? '\0' : ('0' + i));
+		data->watchdog_miscdev.name = data->watchdog_name;
+		data->watchdog_miscdev.fops = &watchdog_fops;
+		data->watchdog_miscdev.minor = watchdog_minors[i];
+
+		err = misc_register(&data->watchdog_miscdev);
+		if (err == -EBUSY)
+			continue;
+		if (err) {
+			data->watchdog_miscdev.minor = 0;
+			dev_err(&client->dev,
+				"Registering watchdog chardev: %d\n", err);
+			break;
+		}
+
+		list_add(&data->list, &watchdog_data_list);
+
+		dev_info(&client->dev,
+			"Registered watchdog chardev major 10, minor: %d\n",
+			watchdog_minors[i]);
+		break;
+	}
+	if (i == ARRAY_SIZE(watchdog_minors)) {
+		data->watchdog_miscdev.minor = 0;
+		dev_warn(&client->dev,
+			 "Couldn't register watchdog chardev (due to no free minor)\n");
+	}
+
+	mutex_unlock(&watchdog_data_mutex);
+
+	return 0;
+
+	/* Unregister hwmon device */
+
+exit_devunreg:
+
+	hwmon_device_unregister(data->hwmon_dev);
+
+	/* Unregister sysfs hooks */
+
+exit_remove:
+	for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
+		device_remove_file(dev, &w83793_sensor_attr_2[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
+		device_remove_file(dev, &sda_single_files[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
+		device_remove_file(dev, &w83793_vid[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
+		device_remove_file(dev, &w83793_left_fan[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
+		device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
+
+	for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
+		device_remove_file(dev, &w83793_temp[i].dev_attr);
+
+	if (data->lm75[0] != NULL)
+		i2c_unregister_device(data->lm75[0]);
+	if (data->lm75[1] != NULL)
+		i2c_unregister_device(data->lm75[1]);
+free_mem:
+	kfree(data);
+exit:
+	return err;
+}
+
+static void w83793_update_nonvolatile(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	int i, j;
+	/*
+	 * They are somewhat "stable" registers, and to update them every time
+	 * takes so much time, it's just not worthy. Update them in a long
+	 * interval to avoid exception.
+	 */
+	if (!(time_after(jiffies, data->last_nonvolatile + HZ * 300)
+	      || !data->valid))
+		return;
+	/* update voltage limits */
+	for (i = 1; i < 3; i++) {
+		for (j = 0; j < ARRAY_SIZE(data->in); j++) {
+			data->in[j][i] =
+			    w83793_read_value(client, W83793_REG_IN[j][i]);
+		}
+		data->in_low_bits[i] =
+		    w83793_read_value(client, W83793_REG_IN_LOW_BITS[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+		/* Update the Fan measured value and limits */
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan_min[i] =
+		    w83793_read_value(client, W83793_REG_FAN_MIN(i)) << 8;
+		data->fan_min[i] |=
+		    w83793_read_value(client, W83793_REG_FAN_MIN(i) + 1);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->temp_fan_map); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		data->temp_fan_map[i] =
+		    w83793_read_value(client, W83793_REG_TEMP_FAN_MAP(i));
+		for (j = 1; j < 5; j++) {
+			data->temp[i][j] =
+			    w83793_read_value(client, W83793_REG_TEMP[i][j]);
+		}
+		data->temp_cruise[i] =
+		    w83793_read_value(client, W83793_REG_TEMP_CRUISE(i));
+		for (j = 0; j < 7; j++) {
+			data->sf2_pwm[i][j] =
+			    w83793_read_value(client, W83793_REG_SF2_PWM(i, j));
+			data->sf2_temp[i][j] =
+			    w83793_read_value(client,
+					      W83793_REG_SF2_TEMP(i, j));
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->temp_mode); i++)
+		data->temp_mode[i] =
+		    w83793_read_value(client, W83793_REG_TEMP_MODE[i]);
+
+	for (i = 0; i < ARRAY_SIZE(data->tolerance); i++) {
+		data->tolerance[i] =
+		    w83793_read_value(client, W83793_REG_TEMP_TOL(i));
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
+		if (!(data->has_pwm & (1 << i)))
+			continue;
+		data->pwm[i][PWM_NONSTOP] =
+		    w83793_read_value(client, W83793_REG_PWM(i, PWM_NONSTOP));
+		data->pwm[i][PWM_START] =
+		    w83793_read_value(client, W83793_REG_PWM(i, PWM_START));
+		data->pwm_stop_time[i] =
+		    w83793_read_value(client, W83793_REG_PWM_STOP_TIME(i));
+	}
+
+	data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT);
+	data->pwm_enable = w83793_read_value(client, W83793_REG_PWM_ENABLE);
+	data->pwm_uptime = w83793_read_value(client, W83793_REG_PWM_UPTIME);
+	data->pwm_downtime = w83793_read_value(client, W83793_REG_PWM_DOWNTIME);
+	data->temp_critical =
+	    w83793_read_value(client, W83793_REG_TEMP_CRITICAL);
+	data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP);
+
+	for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
+		data->beeps[i] = w83793_read_value(client, W83793_REG_BEEP(i));
+
+	data->last_nonvolatile = jiffies;
+}
+
+static struct w83793_data *w83793_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83793_data *data = i2c_get_clientdata(client);
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!(time_after(jiffies, data->last_updated + HZ * 2)
+	      || !data->valid))
+		goto END;
+
+	/* Update the voltages measured value and limits */
+	for (i = 0; i < ARRAY_SIZE(data->in); i++)
+		data->in[i][IN_READ] =
+		    w83793_read_value(client, W83793_REG_IN[i][IN_READ]);
+
+	data->in_low_bits[IN_READ] =
+	    w83793_read_value(client, W83793_REG_IN_LOW_BITS[IN_READ]);
+
+	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan[i] =
+		    w83793_read_value(client, W83793_REG_FAN(i)) << 8;
+		data->fan[i] |=
+		    w83793_read_value(client, W83793_REG_FAN(i) + 1);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		data->temp[i][TEMP_READ] =
+		    w83793_read_value(client, W83793_REG_TEMP[i][TEMP_READ]);
+	}
+
+	data->temp_low_bits =
+	    w83793_read_value(client, W83793_REG_TEMP_LOW_BITS);
+
+	for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
+		if (data->has_pwm & (1 << i))
+			data->pwm[i][PWM_DUTY] =
+			    w83793_read_value(client,
+					      W83793_REG_PWM(i, PWM_DUTY));
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
+		data->alarms[i] =
+		    w83793_read_value(client, W83793_REG_ALARM(i));
+	if (data->has_vid & 0x01)
+		data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA);
+	if (data->has_vid & 0x02)
+		data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB);
+	w83793_update_nonvolatile(dev);
+	data->last_updated = jiffies;
+	data->valid = 1;
+
+END:
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Ignore the possibility that somebody change bank outside the driver
+ * Must be called with data->update_lock held, except during initialization
+ */
+static u8 w83793_read_value(struct i2c_client *client, u16 reg)
+{
+	struct w83793_data *data = i2c_get_clientdata(client);
+	u8 res = 0xff;
+	u8 new_bank = reg >> 8;
+
+	new_bank |= data->bank & 0xfc;
+	if (data->bank != new_bank) {
+		if (i2c_smbus_write_byte_data
+		    (client, W83793_REG_BANKSEL, new_bank) >= 0)
+			data->bank = new_bank;
+		else {
+			dev_err(&client->dev,
+				"set bank to %d failed, fall back "
+				"to bank %d, read reg 0x%x error\n",
+				new_bank, data->bank, reg);
+			res = 0x0;	/* read 0x0 from the chip */
+			goto END;
+		}
+	}
+	res = i2c_smbus_read_byte_data(client, reg & 0xff);
+END:
+	return res;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value)
+{
+	struct w83793_data *data = i2c_get_clientdata(client);
+	int res;
+	u8 new_bank = reg >> 8;
+
+	new_bank |= data->bank & 0xfc;
+	if (data->bank != new_bank) {
+		res = i2c_smbus_write_byte_data(client, W83793_REG_BANKSEL,
+						new_bank);
+		if (res < 0) {
+			dev_err(&client->dev,
+				"set bank to %d failed, fall back "
+				"to bank %d, write reg 0x%x error\n",
+				new_bank, data->bank, reg);
+			goto END;
+		}
+		data->bank = new_bank;
+	}
+
+	res = i2c_smbus_write_byte_data(client, reg & 0xff, value);
+END:
+	return res;
+}
+
+module_i2c_driver(w83793_driver);
+
+MODULE_AUTHOR("Yuan Mu, Sven Anders");
+MODULE_DESCRIPTION("w83793 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
new file mode 100644
index 0000000..49276bb
--- /dev/null
+++ b/drivers/hwmon/w83795.c
@@ -0,0 +1,2285 @@
+/*
+ *  w83795.c - Linux kernel driver for hardware monitoring
+ *  Copyright (C) 2008 Nuvoton Technology Corp.
+ *                Wei Song
+ *  Copyright (C) 2010 Jean Delvare <jdelvare@suse.de>
+ *
+ *  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.
+ *
+ *  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.
+ *
+ *  Supports following chips:
+ *
+ *  Chip       #vin   #fanin #pwm #temp #dts wchipid  vendid  i2c  ISA
+ *  w83795g     21     14     8     6     8    0x79   0x5ca3  yes   no
+ *  w83795adg   18     14     2     6     8    0x79   0x5ca3  yes   no
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/util_macros.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
+};
+
+
+static bool reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+
+#define W83795_REG_BANKSEL		0x00
+#define W83795_REG_VENDORID		0xfd
+#define W83795_REG_CHIPID		0xfe
+#define W83795_REG_DEVICEID		0xfb
+#define W83795_REG_DEVICEID_A		0xff
+
+#define W83795_REG_I2C_ADDR		0xfc
+#define W83795_REG_CONFIG		0x01
+#define W83795_REG_CONFIG_CONFIG48	0x04
+#define W83795_REG_CONFIG_START	0x01
+
+/* Multi-Function Pin Ctrl Registers */
+#define W83795_REG_VOLT_CTRL1		0x02
+#define W83795_REG_VOLT_CTRL2		0x03
+#define W83795_REG_TEMP_CTRL1		0x04
+#define W83795_REG_TEMP_CTRL2		0x05
+#define W83795_REG_FANIN_CTRL1		0x06
+#define W83795_REG_FANIN_CTRL2		0x07
+#define W83795_REG_VMIGB_CTRL		0x08
+
+#define TEMP_READ			0
+#define TEMP_CRIT			1
+#define TEMP_CRIT_HYST			2
+#define TEMP_WARN			3
+#define TEMP_WARN_HYST			4
+/*
+ * only crit and crit_hyst affect real-time alarm status
+ * current crit crit_hyst warn warn_hyst
+ */
+static const u16 W83795_REG_TEMP[][5] = {
+	{0x21, 0x96, 0x97, 0x98, 0x99},	/* TD1/TR1 */
+	{0x22, 0x9a, 0x9b, 0x9c, 0x9d},	/* TD2/TR2 */
+	{0x23, 0x9e, 0x9f, 0xa0, 0xa1},	/* TD3/TR3 */
+	{0x24, 0xa2, 0xa3, 0xa4, 0xa5},	/* TD4/TR4 */
+	{0x1f, 0xa6, 0xa7, 0xa8, 0xa9},	/* TR5 */
+	{0x20, 0xaa, 0xab, 0xac, 0xad},	/* TR6 */
+};
+
+#define IN_READ				0
+#define IN_MAX				1
+#define IN_LOW				2
+static const u16 W83795_REG_IN[][3] = {
+	/* Current, HL, LL */
+	{0x10, 0x70, 0x71},	/* VSEN1 */
+	{0x11, 0x72, 0x73},	/* VSEN2 */
+	{0x12, 0x74, 0x75},	/* VSEN3 */
+	{0x13, 0x76, 0x77},	/* VSEN4 */
+	{0x14, 0x78, 0x79},	/* VSEN5 */
+	{0x15, 0x7a, 0x7b},	/* VSEN6 */
+	{0x16, 0x7c, 0x7d},	/* VSEN7 */
+	{0x17, 0x7e, 0x7f},	/* VSEN8 */
+	{0x18, 0x80, 0x81},	/* VSEN9 */
+	{0x19, 0x82, 0x83},	/* VSEN10 */
+	{0x1A, 0x84, 0x85},	/* VSEN11 */
+	{0x1B, 0x86, 0x87},	/* VTT */
+	{0x1C, 0x88, 0x89},	/* 3VDD */
+	{0x1D, 0x8a, 0x8b},	/* 3VSB */
+	{0x1E, 0x8c, 0x8d},	/* VBAT */
+	{0x1F, 0xa6, 0xa7},	/* VSEN12 */
+	{0x20, 0xaa, 0xab},	/* VSEN13 */
+	{0x21, 0x96, 0x97},	/* VSEN14 */
+	{0x22, 0x9a, 0x9b},	/* VSEN15 */
+	{0x23, 0x9e, 0x9f},	/* VSEN16 */
+	{0x24, 0xa2, 0xa3},	/* VSEN17 */
+};
+#define W83795_REG_VRLSB		0x3C
+
+static const u8 W83795_REG_IN_HL_LSB[] = {
+	0x8e,	/* VSEN1-4 */
+	0x90,	/* VSEN5-8 */
+	0x92,	/* VSEN9-11 */
+	0x94,	/* VTT, 3VDD, 3VSB, 3VBAT */
+	0xa8,	/* VSEN12 */
+	0xac,	/* VSEN13 */
+	0x98,	/* VSEN14 */
+	0x9c,	/* VSEN15 */
+	0xa0,	/* VSEN16 */
+	0xa4,	/* VSEN17 */
+};
+
+#define IN_LSB_REG(index, type) \
+	(((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \
+	: (W83795_REG_IN_HL_LSB[(index)] + 1))
+
+#define IN_LSB_SHIFT			0
+#define IN_LSB_IDX			1
+static const u8 IN_LSB_SHIFT_IDX[][2] = {
+	/* High/Low LSB shift, LSB No. */
+	{0x00, 0x00},	/* VSEN1 */
+	{0x02, 0x00},	/* VSEN2 */
+	{0x04, 0x00},	/* VSEN3 */
+	{0x06, 0x00},	/* VSEN4 */
+	{0x00, 0x01},	/* VSEN5 */
+	{0x02, 0x01},	/* VSEN6 */
+	{0x04, 0x01},	/* VSEN7 */
+	{0x06, 0x01},	/* VSEN8 */
+	{0x00, 0x02},	/* VSEN9 */
+	{0x02, 0x02},	/* VSEN10 */
+	{0x04, 0x02},	/* VSEN11 */
+	{0x00, 0x03},	/* VTT */
+	{0x02, 0x03},	/* 3VDD */
+	{0x04, 0x03},	/* 3VSB	*/
+	{0x06, 0x03},	/* VBAT	*/
+	{0x06, 0x04},	/* VSEN12 */
+	{0x06, 0x05},	/* VSEN13 */
+	{0x06, 0x06},	/* VSEN14 */
+	{0x06, 0x07},	/* VSEN15 */
+	{0x06, 0x08},	/* VSEN16 */
+	{0x06, 0x09},	/* VSEN17 */
+};
+
+
+#define W83795_REG_FAN(index)		(0x2E + (index))
+#define W83795_REG_FAN_MIN_HL(index)	(0xB6 + (index))
+#define W83795_REG_FAN_MIN_LSB(index)	(0xC4 + (index) / 2)
+#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \
+	(((index) & 1) ? 4 : 0)
+
+#define W83795_REG_VID_CTRL		0x6A
+
+#define W83795_REG_ALARM_CTRL		0x40
+#define ALARM_CTRL_RTSACS		(1 << 7)
+#define W83795_REG_ALARM(index)		(0x41 + (index))
+#define W83795_REG_CLR_CHASSIS		0x4D
+#define W83795_REG_BEEP(index)		(0x50 + (index))
+
+#define W83795_REG_OVT_CFG		0x58
+#define OVT_CFG_SEL			(1 << 7)
+
+
+#define W83795_REG_FCMS1		0x201
+#define W83795_REG_FCMS2		0x208
+#define W83795_REG_TFMR(index)		(0x202 + (index))
+#define W83795_REG_FOMC			0x20F
+
+#define W83795_REG_TSS(index)		(0x209 + (index))
+
+#define TSS_MAP_RESERVED		0xff
+static const u8 tss_map[4][6] = {
+	{ 0,  1,  2,  3,  4,  5},
+	{ 6,  7,  8,  9,  0,  1},
+	{10, 11, 12, 13,  2,  3},
+	{ 4,  5,  4,  5, TSS_MAP_RESERVED, TSS_MAP_RESERVED},
+};
+
+#define PWM_OUTPUT			0
+#define PWM_FREQ			1
+#define PWM_START			2
+#define PWM_NONSTOP			3
+#define PWM_STOP_TIME			4
+#define W83795_REG_PWM(index, nr)	(0x210 + (nr) * 8 + (index))
+
+#define W83795_REG_FTSH(index)		(0x240 + (index) * 2)
+#define W83795_REG_FTSL(index)		(0x241 + (index) * 2)
+#define W83795_REG_TFTS			0x250
+
+#define TEMP_PWM_TTTI			0
+#define TEMP_PWM_CTFS			1
+#define TEMP_PWM_HCT			2
+#define TEMP_PWM_HOT			3
+#define W83795_REG_TTTI(index)		(0x260 + (index))
+#define W83795_REG_CTFS(index)		(0x268 + (index))
+#define W83795_REG_HT(index)		(0x270 + (index))
+
+#define SF4_TEMP			0
+#define SF4_PWM				1
+#define W83795_REG_SF4_TEMP(temp_num, index) \
+	(0x280 + 0x10 * (temp_num) + (index))
+#define W83795_REG_SF4_PWM(temp_num, index) \
+	(0x288 + 0x10 * (temp_num) + (index))
+
+#define W83795_REG_DTSC			0x301
+#define W83795_REG_DTSE			0x302
+#define W83795_REG_DTS(index)		(0x26 + (index))
+#define W83795_REG_PECI_TBASE(index)	(0x320 + (index))
+
+#define DTS_CRIT			0
+#define DTS_CRIT_HYST			1
+#define DTS_WARN			2
+#define DTS_WARN_HYST			3
+#define W83795_REG_DTS_EXT(index)	(0xB2 + (index))
+
+#define SETUP_PWM_DEFAULT		0
+#define SETUP_PWM_UPTIME		1
+#define SETUP_PWM_DOWNTIME		2
+#define W83795_REG_SETUP_PWM(index)    (0x20C + (index))
+
+static inline u16 in_from_reg(u8 index, u16 val)
+{
+	/* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */
+	if (index >= 12 && index <= 14)
+		return val * 6;
+	else
+		return val * 2;
+}
+
+static inline u16 in_to_reg(u8 index, u16 val)
+{
+	if (index >= 12 && index <= 14)
+		return val / 6;
+	else
+		return val / 2;
+}
+
+static inline unsigned long fan_from_reg(u16 val)
+{
+	if ((val == 0xfff) || (val == 0))
+		return 0;
+	return 1350000UL / val;
+}
+
+static inline u16 fan_to_reg(long rpm)
+{
+	if (rpm <= 0)
+		return 0x0fff;
+	return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+}
+
+static inline unsigned long time_from_reg(u8 reg)
+{
+	return reg * 100;
+}
+
+static inline u8 time_to_reg(unsigned long val)
+{
+	return clamp_val((val + 50) / 100, 0, 0xff);
+}
+
+static inline long temp_from_reg(s8 reg)
+{
+	return reg * 1000;
+}
+
+static inline s8 temp_to_reg(long val, s8 min, s8 max)
+{
+	return clamp_val(val / 1000, min, max);
+}
+
+static const u16 pwm_freq_cksel0[16] = {
+	1024, 512, 341, 256, 205, 171, 146, 128,
+	85, 64, 32, 16, 8, 4, 2, 1
+};
+
+static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin)
+{
+	unsigned long base_clock;
+
+	if (reg & 0x80) {
+		base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+		return base_clock / ((reg & 0x7f) + 1);
+	} else
+		return pwm_freq_cksel0[reg & 0x0f];
+}
+
+static u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
+{
+	unsigned long base_clock;
+	u8 reg0, reg1;
+	unsigned long best0, best1;
+
+	/* Best fit for cksel = 0 */
+	reg0 = find_closest_descending(val, pwm_freq_cksel0,
+				       ARRAY_SIZE(pwm_freq_cksel0));
+	if (val < 375)	/* cksel = 1 can't beat this */
+		return reg0;
+	best0 = pwm_freq_cksel0[reg0];
+
+	/* Best fit for cksel = 1 */
+	base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+	reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
+	best1 = base_clock / reg1;
+	reg1 = 0x80 | (reg1 - 1);
+
+	/* Choose the closest one */
+	if (abs(val - best0) > abs(val - best1))
+		return reg1;
+	else
+		return reg0;
+}
+
+enum chip_types {w83795g, w83795adg};
+
+struct w83795_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+	enum chip_types chip_type;
+
+	u8 bank;
+
+	u32 has_in;		/* Enable monitor VIN or not */
+	u8 has_dyn_in;		/* Only in2-0 can have this */
+	u16 in[21][3];		/* Register value, read/high/low */
+	u8 in_lsb[10][3];	/* LSB Register value, high/low */
+	u8 has_gain;		/* has gain: in17-20 * 8 */
+
+	u16 has_fan;		/* Enable fan14-1 or not */
+	u16 fan[14];		/* Register value combine */
+	u16 fan_min[14];	/* Register value combine */
+
+	u8 has_temp;		/* Enable monitor temp6-1 or not */
+	s8 temp[6][5];		/* current, crit, crit_hyst, warn, warn_hyst */
+	u8 temp_read_vrlsb[6];
+	u8 temp_mode;		/* Bit vector, 0 = TR, 1 = TD */
+	u8 temp_src[3];		/* Register value */
+
+	u8 enable_dts;		/*
+				 * Enable PECI and SB-TSI,
+				 * bit 0: =1 enable, =0 disable,
+				 * bit 1: =1 AMD SB-TSI, =0 Intel PECI
+				 */
+	u8 has_dts;		/* Enable monitor DTS temp */
+	s8 dts[8];		/* Register value */
+	u8 dts_read_vrlsb[8];	/* Register value */
+	s8 dts_ext[4];		/* Register value */
+
+	u8 has_pwm;		/*
+				 * 795g supports 8 pwm, 795adg only supports 2,
+				 * no config register, only affected by chip
+				 * type
+				 */
+	u8 pwm[8][5];		/*
+				 * Register value, output, freq, start,
+				 *  non stop, stop time
+				 */
+	u16 clkin;		/* CLKIN frequency in kHz */
+	u8 pwm_fcms[2];		/* Register value */
+	u8 pwm_tfmr[6];		/* Register value */
+	u8 pwm_fomc;		/* Register value */
+
+	u16 target_speed[8];	/*
+				 * Register value, target speed for speed
+				 * cruise
+				 */
+	u8 tol_speed;		/* tolerance of target speed */
+	u8 pwm_temp[6][4];	/* TTTI, CTFS, HCT, HOT */
+	u8 sf4_reg[6][2][7];	/* 6 temp, temp/dcpwm, 7 registers */
+
+	u8 setup_pwm[3];	/* Register value */
+
+	u8 alarms[6];		/* Register value */
+	u8 enable_beep;
+	u8 beeps[6];		/* Register value */
+
+	char valid;
+	char valid_limits;
+	char valid_pwm_config;
+};
+
+/*
+ * Hardware access
+ * We assume that nobdody can change the bank outside the driver.
+ */
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83795_set_bank(struct i2c_client *client, u8 bank)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int err;
+
+	/* If the same bank is already set, nothing to do */
+	if ((data->bank & 0x07) == bank)
+		return 0;
+
+	/* Change to new bank, preserve all other bits */
+	bank |= data->bank & ~0x07;
+	err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to set bank to %d, err %d\n",
+			(int)bank, err);
+		return err;
+	}
+	data->bank = bank;
+
+	return 0;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static u8 w83795_read(struct i2c_client *client, u16 reg)
+{
+	int err;
+
+	err = w83795_set_bank(client, reg >> 8);
+	if (err < 0)
+		return 0x00;	/* Arbitrary */
+
+	err = i2c_smbus_read_byte_data(client, reg & 0xff);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to read from register 0x%03x, err %d\n",
+			(int)reg, err);
+		return 0x00;	/* Arbitrary */
+	}
+	return err;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83795_write(struct i2c_client *client, u16 reg, u8 value)
+{
+	int err;
+
+	err = w83795_set_bank(client, reg >> 8);
+	if (err < 0)
+		return err;
+
+	err = i2c_smbus_write_byte_data(client, reg & 0xff, value);
+	if (err < 0)
+		dev_err(&client->dev,
+			"Failed to write to register 0x%03x, err %d\n",
+			(int)reg, err);
+	return err;
+}
+
+static void w83795_update_limits(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int i, limit;
+	u8 lsb;
+
+	/* Read the voltage limits */
+	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		data->in[i][IN_MAX] =
+			w83795_read(client, W83795_REG_IN[i][IN_MAX]);
+		data->in[i][IN_LOW] =
+			w83795_read(client, W83795_REG_IN[i][IN_LOW]);
+	}
+	for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) {
+		if ((i == 2 && data->chip_type == w83795adg) ||
+		    (i >= 4 && !(data->has_in & (1 << (i + 11)))))
+			continue;
+		data->in_lsb[i][IN_MAX] =
+			w83795_read(client, IN_LSB_REG(i, IN_MAX));
+		data->in_lsb[i][IN_LOW] =
+			w83795_read(client, IN_LSB_REG(i, IN_LOW));
+	}
+
+	/* Read the fan limits */
+	lsb = 0; /* Silent false gcc warning */
+	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+		/*
+		 * Each register contains LSB for 2 fans, but we want to
+		 * read it only once to save time
+		 */
+		if ((i & 1) == 0 && (data->has_fan & (3 << i)))
+			lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
+
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan_min[i] =
+			w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4;
+		data->fan_min[i] |=
+			(lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F;
+	}
+
+	/* Read the temperature limits */
+	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++)
+			data->temp[i][limit] =
+				w83795_read(client, W83795_REG_TEMP[i][limit]);
+	}
+
+	/* Read the DTS limits */
+	if (data->enable_dts) {
+		for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++)
+			data->dts_ext[limit] =
+				w83795_read(client, W83795_REG_DTS_EXT(limit));
+	}
+
+	/* Read beep settings */
+	if (data->enable_beep) {
+		for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
+			data->beeps[i] =
+				w83795_read(client, W83795_REG_BEEP(i));
+	}
+
+	data->valid_limits = 1;
+}
+
+static struct w83795_data *w83795_update_pwm_config(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int i, tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->valid_pwm_config)
+		goto END;
+
+	/* Read temperature source selection */
+	for (i = 0; i < ARRAY_SIZE(data->temp_src); i++)
+		data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i));
+
+	/* Read automatic fan speed control settings */
+	data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1);
+	data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2);
+	for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++)
+		data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i));
+	data->pwm_fomc = w83795_read(client, W83795_REG_FOMC);
+	for (i = 0; i < data->has_pwm; i++) {
+		for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++)
+			data->pwm[i][tmp] =
+				w83795_read(client, W83795_REG_PWM(i, tmp));
+	}
+	for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) {
+		data->target_speed[i] =
+			w83795_read(client, W83795_REG_FTSH(i)) << 4;
+		data->target_speed[i] |=
+			w83795_read(client, W83795_REG_FTSL(i)) >> 4;
+	}
+	data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f;
+
+	for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) {
+		data->pwm_temp[i][TEMP_PWM_TTTI] =
+			w83795_read(client, W83795_REG_TTTI(i)) & 0x7f;
+		data->pwm_temp[i][TEMP_PWM_CTFS] =
+			w83795_read(client, W83795_REG_CTFS(i));
+		tmp = w83795_read(client, W83795_REG_HT(i));
+		data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4;
+		data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f;
+	}
+
+	/* Read SmartFanIV trip points */
+	for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) {
+		for (tmp = 0; tmp < 7; tmp++) {
+			data->sf4_reg[i][SF4_TEMP][tmp] =
+				w83795_read(client,
+					    W83795_REG_SF4_TEMP(i, tmp));
+			data->sf4_reg[i][SF4_PWM][tmp] =
+				w83795_read(client, W83795_REG_SF4_PWM(i, tmp));
+		}
+	}
+
+	/* Read setup PWM */
+	for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++)
+		data->setup_pwm[i] =
+			w83795_read(client, W83795_REG_SETUP_PWM(i));
+
+	data->valid_pwm_config = 1;
+
+END:
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static struct w83795_data *w83795_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	u16 tmp;
+	u8 intrusion;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid_limits)
+		w83795_update_limits(client);
+
+	if (!(time_after(jiffies, data->last_updated + HZ * 2)
+	      || !data->valid))
+		goto END;
+
+	/* Update the voltages value */
+	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2;
+		tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6;
+		data->in[i][IN_READ] = tmp;
+	}
+
+	/* in0-2 can have dynamic limits (W83795G only) */
+	if (data->has_dyn_in) {
+		u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX));
+		u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW));
+
+		for (i = 0; i < 3; i++) {
+			if (!(data->has_dyn_in & (1 << i)))
+				continue;
+			data->in[i][IN_MAX] =
+				w83795_read(client, W83795_REG_IN[i][IN_MAX]);
+			data->in[i][IN_LOW] =
+				w83795_read(client, W83795_REG_IN[i][IN_LOW]);
+			data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03;
+			data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03;
+		}
+	}
+
+	/* Update fan */
+	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
+		data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4;
+	}
+
+	/* Update temperature */
+	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+		data->temp[i][TEMP_READ] =
+			w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]);
+		data->temp_read_vrlsb[i] =
+			w83795_read(client, W83795_REG_VRLSB);
+	}
+
+	/* Update dts temperature */
+	if (data->enable_dts) {
+		for (i = 0; i < ARRAY_SIZE(data->dts); i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			data->dts[i] =
+				w83795_read(client, W83795_REG_DTS(i));
+			data->dts_read_vrlsb[i] =
+				w83795_read(client, W83795_REG_VRLSB);
+		}
+	}
+
+	/* Update pwm output */
+	for (i = 0; i < data->has_pwm; i++) {
+		data->pwm[i][PWM_OUTPUT] =
+		    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
+	}
+
+	/*
+	 * Update intrusion and alarms
+	 * It is important to read intrusion first, because reading from
+	 * register SMI STS6 clears the interrupt status temporarily.
+	 */
+	tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
+	/* Switch to interrupt status for intrusion if needed */
+	if (tmp & ALARM_CTRL_RTSACS)
+		w83795_write(client, W83795_REG_ALARM_CTRL,
+			     tmp & ~ALARM_CTRL_RTSACS);
+	intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6);
+	/* Switch to real-time alarms */
+	w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS);
+	for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
+		data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
+	data->alarms[5] |= intrusion;
+	/* Restore original configuration if needed */
+	if (!(tmp & ALARM_CTRL_RTSACS))
+		w83795_write(client, W83795_REG_ALARM_CTRL,
+			     tmp & ~ALARM_CTRL_RTSACS);
+
+	data->last_updated = jiffies;
+	data->valid = 1;
+
+END:
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs attributes
+ */
+
+#define ALARM_STATUS      0
+#define BEEP_ENABLE       1
+static ssize_t
+show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index >> 3;
+	int bit = sensor_attr->index & 0x07;
+	u8 val;
+
+	if (nr == ALARM_STATUS)
+		val = (data->alarms[index] >> bit) & 1;
+	else		/* BEEP_ENABLE */
+		val = (data->beeps[index] >> bit) & 1;
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index >> 3;
+	int shift = sensor_attr->index & 0x07;
+	u8 beep_bit = 1 << shift;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index));
+	data->beeps[index] &= ~beep_bit;
+	data->beeps[index] |= val << shift;
+	w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* Write 0 to clear chassis alarm */
+static ssize_t
+store_chassis_clear(struct device *dev,
+		    struct device_attribute *attr, const char *buf,
+		    size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0 || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	val = w83795_read(client, W83795_REG_CLR_CHASSIS);
+	val |= 0x80;
+	w83795_write(client, W83795_REG_CLR_CHASSIS, val);
+
+	/* Clear status and force cache refresh */
+	w83795_read(client, W83795_REG_ALARM(5));
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define FAN_INPUT     0
+#define FAN_MIN       1
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	u16 val;
+
+	if (nr == FAN_INPUT)
+		val = data->fan[index] & 0x0fff;
+	else
+		val = data->fan_min[index] & 0x0fff;
+
+	return sprintf(buf, "%lu\n", fan_from_reg(val));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+	val = fan_to_reg(val);
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[index] = val;
+	w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff);
+	val &= 0x0f;
+	if (index & 1) {
+		val <<= 4;
+		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
+		       & 0x0f;
+	} else {
+		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
+		       & 0xf0;
+	}
+	w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data;
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned int val;
+
+	data = nr == PWM_OUTPUT ? w83795_update_device(dev)
+				: w83795_update_pwm_config(dev);
+
+	switch (nr) {
+	case PWM_STOP_TIME:
+		val = time_from_reg(data->pwm[index][nr]);
+		break;
+	case PWM_FREQ:
+		val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin);
+		break;
+	default:
+		val = data->pwm[index][nr];
+		break;
+	}
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case PWM_STOP_TIME:
+		val = time_to_reg(val);
+		break;
+	case PWM_FREQ:
+		val = pwm_freq_to_reg(val, data->clkin);
+		break;
+	default:
+		val = clamp_val(val, 0, 0xff);
+		break;
+	}
+	w83795_write(client, W83795_REG_PWM(index, nr), val);
+	data->pwm[index][nr] = val;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = sensor_attr->index;
+	u8 tmp;
+
+	/* Speed cruise mode */
+	if (data->pwm_fcms[0] & (1 << index)) {
+		tmp = 2;
+		goto out;
+	}
+	/* Thermal cruise or SmartFan IV mode */
+	for (tmp = 0; tmp < 6; tmp++) {
+		if (data->pwm_tfmr[tmp] & (1 << index)) {
+			tmp = 3;
+			goto out;
+		}
+	}
+	/* Manual mode */
+	tmp = 1;
+
+out:
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	unsigned long val;
+	int i;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val < 1 || val > 2)
+		return -EINVAL;
+
+#ifndef CONFIG_SENSORS_W83795_FANCTRL
+	if (val > 1) {
+		dev_warn(dev, "Automatic fan speed control support disabled\n");
+		dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n");
+		return -EOPNOTSUPP;
+	}
+#endif
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 1:
+		/* Clear speed cruise mode bits */
+		data->pwm_fcms[0] &= ~(1 << index);
+		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+		/* Clear thermal cruise mode bits */
+		for (i = 0; i < 6; i++) {
+			data->pwm_tfmr[i] &= ~(1 << index);
+			w83795_write(client, W83795_REG_TFMR(i),
+				data->pwm_tfmr[i]);
+		}
+		break;
+	case 2:
+		data->pwm_fcms[0] |= (1 << index);
+		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+		break;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = to_sensor_dev_attr_2(attr)->index;
+	unsigned int mode;
+
+	if (data->pwm_fomc & (1 << index))
+		mode = 0;	/* DC */
+	else
+		mode = 1;	/* PWM */
+
+	return sprintf(buf, "%u\n", mode);
+}
+
+/*
+ * Check whether a given temperature source can ever be useful.
+ * Returns the number of selectable temperature channels which are
+ * enabled.
+ */
+static int w83795_tss_useful(const struct w83795_data *data, int tsrc)
+{
+	int useful = 0, i;
+
+	for (i = 0; i < 4; i++) {
+		if (tss_map[i][tsrc] == TSS_MAP_RESERVED)
+			continue;
+		if (tss_map[i][tsrc] < 6)	/* Analog */
+			useful += (data->has_temp >> tss_map[i][tsrc]) & 1;
+		else				/* Digital */
+			useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
+	}
+
+	return useful;
+}
+
+static ssize_t
+show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = sensor_attr->index;
+	u8 tmp = data->temp_src[index / 2];
+
+	if (index & 1)
+		tmp >>= 4;	/* Pick high nibble */
+	else
+		tmp &= 0x0f;	/* Pick low nibble */
+
+	/* Look-up the actual temperature channel number */
+	if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED)
+		return -EINVAL;		/* Shouldn't happen */
+
+	return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1);
+}
+
+static ssize_t
+store_temp_src(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int tmp;
+	unsigned long channel;
+	u8 val = index / 2;
+
+	if (kstrtoul(buf, 10, &channel) < 0 ||
+	    channel < 1 || channel > 14)
+		return -EINVAL;
+
+	/* Check if request can be fulfilled */
+	for (tmp = 0; tmp < 4; tmp++) {
+		if (tss_map[tmp][index] == channel - 1)
+			break;
+	}
+	if (tmp == 4)	/* No match */
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (index & 1) {
+		tmp <<= 4;
+		data->temp_src[val] &= 0x0f;
+	} else {
+		data->temp_src[val] &= 0xf0;
+	}
+	data->temp_src[val] |= tmp;
+	w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define TEMP_PWM_ENABLE   0
+#define TEMP_PWM_FAN_MAP  1
+static ssize_t
+show_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	u8 tmp = 0xff;
+
+	switch (nr) {
+	case TEMP_PWM_ENABLE:
+		tmp = (data->pwm_fcms[1] >> index) & 1;
+		if (tmp)
+			tmp = 4;
+		else
+			tmp = 3;
+		break;
+	case TEMP_PWM_FAN_MAP:
+		tmp = data->pwm_tfmr[index];
+		break;
+	}
+
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long tmp;
+
+	if (kstrtoul(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	switch (nr) {
+	case TEMP_PWM_ENABLE:
+		if (tmp != 3 && tmp != 4)
+			return -EINVAL;
+		tmp -= 3;
+		mutex_lock(&data->update_lock);
+		data->pwm_fcms[1] &= ~(1 << index);
+		data->pwm_fcms[1] |= tmp << index;
+		w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]);
+		mutex_unlock(&data->update_lock);
+		break;
+	case TEMP_PWM_FAN_MAP:
+		mutex_lock(&data->update_lock);
+		tmp = clamp_val(tmp, 0, 0xff);
+		w83795_write(client, W83795_REG_TFMR(index), tmp);
+		data->pwm_tfmr[index] = tmp;
+		mutex_unlock(&data->update_lock);
+		break;
+	}
+	return count;
+}
+
+#define FANIN_TARGET   0
+#define FANIN_TOL      1
+static ssize_t
+show_fanin(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	u16 tmp = 0;
+
+	switch (nr) {
+	case FANIN_TARGET:
+		tmp = fan_from_reg(data->target_speed[index]);
+		break;
+	case FANIN_TOL:
+		tmp = data->tol_speed;
+		break;
+	}
+
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_fanin(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case FANIN_TARGET:
+		val = fan_to_reg(clamp_val(val, 0, 0xfff));
+		w83795_write(client, W83795_REG_FTSH(index), val >> 4);
+		w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
+		data->target_speed[index] = val;
+		break;
+	case FANIN_TOL:
+		val = clamp_val(val, 0, 0x3f);
+		w83795_write(client, W83795_REG_TFTS, val);
+		data->tol_speed = val;
+		break;
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static ssize_t
+show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	long tmp = temp_from_reg(data->pwm_temp[index][nr]);
+
+	return sprintf(buf, "%ld\n", tmp);
+}
+
+static ssize_t
+store_temp_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+	u8 tmp;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case TEMP_PWM_TTTI:
+		val = clamp_val(val, 0, 0x7f);
+		w83795_write(client, W83795_REG_TTTI(index), val);
+		break;
+	case TEMP_PWM_CTFS:
+		val = clamp_val(val, 0, 0x7f);
+		w83795_write(client, W83795_REG_CTFS(index), val);
+		break;
+	case TEMP_PWM_HCT:
+		val = clamp_val(val, 0, 0x0f);
+		tmp = w83795_read(client, W83795_REG_HT(index));
+		tmp &= 0x0f;
+		tmp |= (val << 4) & 0xf0;
+		w83795_write(client, W83795_REG_HT(index), tmp);
+		break;
+	case TEMP_PWM_HOT:
+		val = clamp_val(val, 0, 0x0f);
+		tmp = w83795_read(client, W83795_REG_HT(index));
+		tmp &= 0xf0;
+		tmp |= val & 0x0f;
+		w83795_write(client, W83795_REG_HT(index), tmp);
+		break;
+	}
+	data->pwm_temp[index][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+
+	return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]);
+}
+
+static ssize_t
+store_sf4_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	w83795_write(client, W83795_REG_SF4_PWM(index, nr), val);
+	data->sf4_reg[index][SF4_PWM][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+
+	return sprintf(buf, "%u\n",
+		(data->sf4_reg[index][SF4_TEMP][nr]) * 1000);
+}
+
+static ssize_t
+store_sf4_temp(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+	w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val);
+	data->sf4_reg[index][SF4_TEMP][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	long temp = temp_from_reg(data->temp[index][nr]);
+
+	if (nr == TEMP_READ)
+		temp += (data->temp_read_vrlsb[index] >> 6) * 250;
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	long tmp;
+
+	if (kstrtol(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->temp[index][nr] = temp_to_reg(tmp, -128, 127);
+	w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+static ssize_t
+show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	int tmp;
+
+	if (data->enable_dts & 2)
+		tmp = 5;
+	else
+		tmp = 6;
+
+	return sprintf(buf, "%d\n", tmp);
+}
+
+static ssize_t
+show_dts(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	long temp = temp_from_reg(data->dts[index]);
+
+	temp += (data->dts_read_vrlsb[index] >> 6) * 250;
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct w83795_data *data = dev_get_drvdata(dev);
+	long temp = temp_from_reg(data->dts_ext[nr]);
+
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_dts_ext(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	long tmp;
+
+	if (kstrtol(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->dts_ext[nr] = temp_to_reg(tmp, -128, 127);
+	w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+static ssize_t
+show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int tmp;
+
+	if (data->temp_mode & (1 << index))
+		tmp = 3;	/* Thermal diode */
+	else
+		tmp = 4;	/* Thermistor */
+
+	return sprintf(buf, "%d\n", tmp);
+}
+
+/* Only for temp1-4 (temp5-6 can only be thermistor) */
+static ssize_t
+store_temp_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int reg_shift;
+	unsigned long val;
+	u8 tmp;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if ((val != 4) && (val != 3))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (val == 3) {
+		/* Thermal diode */
+		val = 0x01;
+		data->temp_mode |= 1 << index;
+	} else if (val == 4) {
+		/* Thermistor */
+		val = 0x03;
+		data->temp_mode &= ~(1 << index);
+	}
+
+	reg_shift = 2 * index;
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
+	tmp &= ~(0x03 << reg_shift);
+	tmp |= val << reg_shift;
+	w83795_write(client, W83795_REG_TEMP_CTRL2, tmp);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+/* show/store VIN */
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	u16 val = data->in[index][nr];
+	u8 lsb_idx;
+
+	switch (nr) {
+	case IN_READ:
+		/* calculate this value again by sensors as sensors3.conf */
+		if ((index >= 17) &&
+		    !((data->has_gain >> (index - 17)) & 1))
+			val *= 8;
+		break;
+	case IN_MAX:
+	case IN_LOW:
+		lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
+		val <<= 2;
+		val |= (data->in_lsb[lsb_idx][nr] >>
+			IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03;
+		if ((index >= 17) &&
+		    !((data->has_gain >> (index - 17)) & 1))
+			val *= 8;
+		break;
+	}
+	val = in_from_reg(index, val);
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_in(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	u8 tmp;
+	u8 lsb_idx;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val = in_to_reg(index, val);
+
+	if ((index >= 17) &&
+	    !((data->has_gain >> (index - 17)) & 1))
+		val /= 8;
+	val = clamp_val(val, 0, 0x3FF);
+	mutex_lock(&data->update_lock);
+
+	lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
+	tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr));
+	tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]);
+	tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT];
+	w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp);
+	data->in_lsb[lsb_idx][nr] = tmp;
+
+	tmp = (val >> 2) & 0xff;
+	w83795_write(client, W83795_REG_IN[index][nr], tmp);
+	data->in[index][nr] = tmp;
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+static ssize_t
+show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	u16 val = data->setup_pwm[nr];
+
+	switch (nr) {
+	case SETUP_PWM_UPTIME:
+	case SETUP_PWM_DOWNTIME:
+		val = time_from_reg(val);
+		break;
+	}
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_setup(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	switch (nr) {
+	case SETUP_PWM_DEFAULT:
+		val = clamp_val(val, 0, 0xff);
+		break;
+	case SETUP_PWM_UPTIME:
+	case SETUP_PWM_DOWNTIME:
+		val = time_to_reg(val);
+		if (val == 0)
+			return -EINVAL;
+		break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->setup_pwm[nr] = val;
+	w83795_write(client, W83795_REG_SETUP_PWM(nr), val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#endif
+
+
+#define NOT_USED			-1
+
+/*
+ * Don't change the attribute order, _max, _min and _beep are accessed by index
+ * somewhere else in the code
+ */
+#define SENSOR_ATTR_IN(index) {						\
+	SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,	\
+		IN_READ, index), \
+	SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_MAX, index),				\
+	SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_LOW, index),				\
+	SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \
+	SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE,		\
+		index + ((index > 14) ? 1 : 0)) }
+
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
+#define SENSOR_ATTR_FAN(index) {					\
+	SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,		\
+		NULL, FAN_INPUT, index - 1), \
+	SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO,		\
+		show_fan, store_fan_min, FAN_MIN, index - 1),	\
+	SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + 31),			\
+	SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) }
+
+#define SENSOR_ATTR_PWM(index) {					\
+	SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,		\
+		store_pwm, PWM_OUTPUT, index - 1),			\
+	SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,		\
+		show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+	SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,			\
+		show_pwm_mode, NULL, NOT_USED, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_FREQ, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_NONSTOP, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_START, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,	\
+		show_pwm, store_pwm, PWM_STOP_TIME, index - 1),	 \
+	SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
+		show_fanin, store_fanin, FANIN_TARGET, index - 1) }
+
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
+#define SENSOR_ATTR_DTS(index) {					\
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,		\
+		show_dts_mode, NULL, NOT_USED, index - 7),	\
+	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts,		\
+		NULL, NOT_USED, index - 7),				\
+	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \
+		store_dts_ext, DTS_CRIT, NOT_USED),			\
+	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
+		show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED),	\
+	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \
+		store_dts_ext, DTS_WARN, NOT_USED),			\
+	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED),	\
+	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
+		show_alarm_beep, NULL, ALARM_STATUS, index + 17),	\
+	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
+
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
+#define SENSOR_ATTR_TEMP(index) {					\
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
+		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp,		\
+		NULL, TEMP_READ, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_CRIT, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_CRIT_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_WARN, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_WARN_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
+		show_alarm_beep, NULL, ALARM_STATUS,			\
+		index + (index > 4 ? 11 : 17)),				\
+	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE,		\
+		index + (index > 4 ? 11 : 17)),				\
+	SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm_enable, store_temp_pwm_enable,		\
+		TEMP_PWM_ENABLE, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \
+		show_temp_pwm_enable, store_temp_pwm_enable,		\
+		TEMP_PWM_FAN_MAP, index - 1),				\
+	SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO,		\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \
+	SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO,		\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \
+	SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \
+	SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \
+	SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 6, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 6, index - 1) }
+
+
+static struct sensor_device_attribute_2 w83795_in[][5] = {
+	SENSOR_ATTR_IN(0),
+	SENSOR_ATTR_IN(1),
+	SENSOR_ATTR_IN(2),
+	SENSOR_ATTR_IN(3),
+	SENSOR_ATTR_IN(4),
+	SENSOR_ATTR_IN(5),
+	SENSOR_ATTR_IN(6),
+	SENSOR_ATTR_IN(7),
+	SENSOR_ATTR_IN(8),
+	SENSOR_ATTR_IN(9),
+	SENSOR_ATTR_IN(10),
+	SENSOR_ATTR_IN(11),
+	SENSOR_ATTR_IN(12),
+	SENSOR_ATTR_IN(13),
+	SENSOR_ATTR_IN(14),
+	SENSOR_ATTR_IN(15),
+	SENSOR_ATTR_IN(16),
+	SENSOR_ATTR_IN(17),
+	SENSOR_ATTR_IN(18),
+	SENSOR_ATTR_IN(19),
+	SENSOR_ATTR_IN(20),
+};
+
+static const struct sensor_device_attribute_2 w83795_fan[][4] = {
+	SENSOR_ATTR_FAN(1),
+	SENSOR_ATTR_FAN(2),
+	SENSOR_ATTR_FAN(3),
+	SENSOR_ATTR_FAN(4),
+	SENSOR_ATTR_FAN(5),
+	SENSOR_ATTR_FAN(6),
+	SENSOR_ATTR_FAN(7),
+	SENSOR_ATTR_FAN(8),
+	SENSOR_ATTR_FAN(9),
+	SENSOR_ATTR_FAN(10),
+	SENSOR_ATTR_FAN(11),
+	SENSOR_ATTR_FAN(12),
+	SENSOR_ATTR_FAN(13),
+	SENSOR_ATTR_FAN(14),
+};
+
+static const struct sensor_device_attribute_2 w83795_temp[][28] = {
+	SENSOR_ATTR_TEMP(1),
+	SENSOR_ATTR_TEMP(2),
+	SENSOR_ATTR_TEMP(3),
+	SENSOR_ATTR_TEMP(4),
+	SENSOR_ATTR_TEMP(5),
+	SENSOR_ATTR_TEMP(6),
+};
+
+static const struct sensor_device_attribute_2 w83795_dts[][8] = {
+	SENSOR_ATTR_DTS(7),
+	SENSOR_ATTR_DTS(8),
+	SENSOR_ATTR_DTS(9),
+	SENSOR_ATTR_DTS(10),
+	SENSOR_ATTR_DTS(11),
+	SENSOR_ATTR_DTS(12),
+	SENSOR_ATTR_DTS(13),
+	SENSOR_ATTR_DTS(14),
+};
+
+static const struct sensor_device_attribute_2 w83795_pwm[][8] = {
+	SENSOR_ATTR_PWM(1),
+	SENSOR_ATTR_PWM(2),
+	SENSOR_ATTR_PWM(3),
+	SENSOR_ATTR_PWM(4),
+	SENSOR_ATTR_PWM(5),
+	SENSOR_ATTR_PWM(6),
+	SENSOR_ATTR_PWM(7),
+	SENSOR_ATTR_PWM(8),
+};
+
+static const struct sensor_device_attribute_2 w83795_tss[6] = {
+	SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 0),
+	SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 1),
+	SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 2),
+	SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 3),
+	SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 4),
+	SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 5),
+};
+
+static const struct sensor_device_attribute_2 sda_single_files[] = {
+	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_chassis_clear, ALARM_STATUS, 46),
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+	SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
+		store_fanin, FANIN_TOL, NOT_USED),
+	SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
+	SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
+	SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
+#endif
+};
+
+static const struct sensor_device_attribute_2 sda_beep_files[] = {
+	SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_beep, BEEP_ENABLE, 46),
+	SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_beep, BEEP_ENABLE, 47),
+};
+
+/*
+ * Driver interface
+ */
+
+static void w83795_init_client(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	static const u16 clkin[4] = {	/* in kHz */
+		14318, 24000, 33333, 48000
+	};
+	u8 config;
+
+	if (reset)
+		w83795_write(client, W83795_REG_CONFIG, 0x80);
+
+	/* Start monitoring if needed */
+	config = w83795_read(client, W83795_REG_CONFIG);
+	if (!(config & W83795_REG_CONFIG_START)) {
+		dev_info(&client->dev, "Enabling monitoring operations\n");
+		w83795_write(client, W83795_REG_CONFIG,
+			     config | W83795_REG_CONFIG_START);
+	}
+
+	data->clkin = clkin[(config >> 3) & 0x3];
+	dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin);
+}
+
+static int w83795_get_device_id(struct i2c_client *client)
+{
+	int device_id;
+
+	device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
+
+	/*
+	 * Special case for rev. A chips; can't be checked first because later
+	 * revisions emulate this for compatibility
+	 */
+	if (device_id < 0 || (device_id & 0xf0) != 0x50) {
+		int alt_id;
+
+		alt_id = i2c_smbus_read_byte_data(client,
+						  W83795_REG_DEVICEID_A);
+		if (alt_id == 0x50)
+			device_id = alt_id;
+	}
+
+	return device_id;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83795_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	int bank, vendor_id, device_id, expected, i2c_addr, config;
+	struct i2c_adapter *adapter = client->adapter;
+	unsigned short address = client->addr;
+	const char *chip_name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+	bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
+	if (bank < 0 || (bank & 0x7c)) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "bank");
+		return -ENODEV;
+	}
+
+	/* Check Nuvoton vendor ID */
+	vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID);
+	expected = bank & 0x80 ? 0x5c : 0xa3;
+	if (vendor_id != expected) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "vendor id");
+		return -ENODEV;
+	}
+
+	/* Check device ID */
+	device_id = w83795_get_device_id(client) |
+		    (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8);
+	if ((device_id >> 4) != 0x795) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "device id\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
+	 * should match
+	 */
+	if ((bank & 0x07) == 0) {
+		i2c_addr = i2c_smbus_read_byte_data(client,
+						    W83795_REG_I2C_ADDR);
+		if ((i2c_addr & 0x7f) != address) {
+			dev_dbg(&adapter->dev,
+				"w83795: Detection failed at addr 0x%02hx, "
+				"check %s\n", address, "i2c addr");
+			return -ENODEV;
+		}
+	}
+
+	/*
+	 * Check 795 chip type: 795G or 795ADG
+	 * Usually we don't write to chips during detection, but here we don't
+	 * quite have the choice; hopefully it's OK, we are about to return
+	 * success anyway
+	 */
+	if ((bank & 0x07) != 0)
+		i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
+					  bank & ~0x07);
+	config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG);
+	if (config & W83795_REG_CONFIG_CONFIG48)
+		chip_name = "w83795adg";
+	else
+		chip_name = "w83795g";
+
+	strlcpy(info->type, chip_name, I2C_NAME_SIZE);
+	dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name,
+		 'A' + (device_id & 0xf), address);
+
+	return 0;
+}
+
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+#define NUM_PWM_ATTRIBUTES	ARRAY_SIZE(w83795_pwm[0])
+#define NUM_TEMP_ATTRIBUTES	ARRAY_SIZE(w83795_temp[0])
+#else
+#define NUM_PWM_ATTRIBUTES	4
+#define NUM_TEMP_ATTRIBUTES	8
+#endif
+
+static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
+			       const struct device_attribute *))
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	int err, i, j;
+
+	for (i = 0; i < ARRAY_SIZE(w83795_in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) {
+			if (j == 4 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_in[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) {
+			if (j == 3 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_fan[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
+		j = w83795_tss_useful(data, i);
+		if (!j)
+			continue;
+		err = fn(dev, &w83795_tss[i].dev_attr);
+		if (err)
+			return err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
+		err = fn(dev, &sda_single_files[i].dev_attr);
+		if (err)
+			return err;
+	}
+
+	if (data->enable_beep) {
+		for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
+			err = fn(dev, &sda_beep_files[i].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < data->has_pwm; i++) {
+		for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
+			err = fn(dev, &w83795_pwm[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) {
+			if (j == 7 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_temp[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	if (data->enable_dts) {
+		for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) {
+				if (j == 7 && !data->enable_beep)
+					continue;
+				err = fn(dev, &w83795_dts[i][j].dev_attr);
+				if (err)
+					return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* We need a wrapper that fits in w83795_handle_files */
+static int device_remove_file_wrapper(struct device *dev,
+				      const struct device_attribute *attr)
+{
+	device_remove_file(dev, attr);
+	return 0;
+}
+
+static void w83795_check_dynamic_in_limits(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	u8 vid_ctl;
+	int i, err_max, err_min;
+
+	vid_ctl = w83795_read(client, W83795_REG_VID_CTRL);
+
+	/* Return immediately if VRM isn't configured */
+	if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07)
+		return;
+
+	data->has_dyn_in = (vid_ctl >> 3) & 0x07;
+	for (i = 0; i < 2; i++) {
+		if (!(data->has_dyn_in & (1 << i)))
+			continue;
+
+		/* Voltage limits in dynamic mode, switch to read-only */
+		err_max = sysfs_chmod_file(&client->dev.kobj,
+					   &w83795_in[i][2].dev_attr.attr,
+					   S_IRUGO);
+		err_min = sysfs_chmod_file(&client->dev.kobj,
+					   &w83795_in[i][3].dev_attr.attr,
+					   S_IRUGO);
+		if (err_max || err_min)
+			dev_warn(&client->dev,
+				 "Failed to set in%d limits read-only (%d, %d)\n",
+				 i, err_max, err_min);
+		else
+			dev_info(&client->dev,
+				 "in%d limits set dynamically from VID\n", i);
+	}
+}
+
+/* Check pins that can be used for either temperature or voltage monitoring */
+static void w83795_apply_temp_config(struct w83795_data *data, u8 config,
+				     int temp_chan, int in_chan)
+{
+	/* config is a 2-bit value */
+	switch (config) {
+	case 0x2: /* Voltage monitoring */
+		data->has_in |= 1 << in_chan;
+		break;
+	case 0x1: /* Thermal diode */
+		if (temp_chan >= 4)
+			break;
+		data->temp_mode |= 1 << temp_chan;
+		/* fall through */
+	case 0x3: /* Thermistor */
+		data->has_temp |= 1 << temp_chan;
+		break;
+	}
+}
+
+static int w83795_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int i;
+	u8 tmp;
+	struct device *dev = &client->dev;
+	struct w83795_data *data;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->chip_type = id->driver_data;
+	data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the chip */
+	w83795_init_client(client);
+
+	/* Check which voltages and fans are present */
+	data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1)
+		     | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8);
+	data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1)
+		      | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8);
+
+	/* Check which analog temperatures and extra voltages are present */
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL1);
+	if (tmp & 0x20)
+		data->enable_dts = 1;
+	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16);
+	w83795_apply_temp_config(data, tmp & 0x3, 4, 15);
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
+	w83795_apply_temp_config(data, tmp >> 6, 3, 20);
+	w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19);
+	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18);
+	w83795_apply_temp_config(data, tmp & 0x3, 0, 17);
+
+	/* Check DTS enable status */
+	if (data->enable_dts) {
+		if (1 & w83795_read(client, W83795_REG_DTSC))
+			data->enable_dts |= 2;
+		data->has_dts = w83795_read(client, W83795_REG_DTSE);
+	}
+
+	/* Report PECI Tbase values */
+	if (data->enable_dts == 1) {
+		for (i = 0; i < 8; i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			tmp = w83795_read(client, W83795_REG_PECI_TBASE(i));
+			dev_info(&client->dev,
+				 "PECI agent %d Tbase temperature: %u\n",
+				 i + 1, (unsigned int)tmp & 0x7f);
+		}
+	}
+
+	data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f;
+
+	/* pwm and smart fan */
+	if (data->chip_type == w83795g)
+		data->has_pwm = 8;
+	else
+		data->has_pwm = 2;
+
+	/* Check if BEEP pin is available */
+	if (data->chip_type == w83795g) {
+		/* The W83795G has a dedicated BEEP pin */
+		data->enable_beep = 1;
+	} else {
+		/*
+		 * The W83795ADG has a shared pin for OVT# and BEEP, so you
+		 * can't have both
+		 */
+		tmp = w83795_read(client, W83795_REG_OVT_CFG);
+		if ((tmp & OVT_CFG_SEL) == 0)
+			data->enable_beep = 1;
+	}
+
+	err = w83795_handle_files(dev, device_create_file);
+	if (err)
+		goto exit_remove;
+
+	if (data->chip_type == w83795g)
+		w83795_check_dynamic_in_limits(client);
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	w83795_handle_files(dev, device_remove_file_wrapper);
+	return err;
+}
+
+static int w83795_remove(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	w83795_handle_files(&client->dev, device_remove_file_wrapper);
+
+	return 0;
+}
+
+
+static const struct i2c_device_id w83795_id[] = {
+	{ "w83795g", w83795g },
+	{ "w83795adg", w83795adg },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83795_id);
+
+static struct i2c_driver w83795_driver = {
+	.driver = {
+		   .name = "w83795",
+	},
+	.probe		= w83795_probe,
+	.remove		= w83795_remove,
+	.id_table	= w83795_id,
+
+	.class		= I2C_CLASS_HWMON,
+	.detect		= w83795_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(w83795_driver);
+
+MODULE_AUTHOR("Wei Song, Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
new file mode 100644
index 0000000..ac30431
--- /dev/null
+++ b/drivers/hwmon/w83l785ts.c
@@ -0,0 +1,300 @@
+/*
+ * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
+ *               monitoring
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
+ *
+ * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
+ * by Winbond. It reports a single external temperature with a 1 deg
+ * resolution and a 3 deg accuracy. Datasheet can be obtained from
+ * Winbond's website at:
+ *   http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
+ *
+ * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
+ * <jdelvare@suse.de>.
+ *
+ * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
+ * error handling mechanism.
+ *
+ * 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/delay.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>
+
+/* How many retries on register read error */
+#define MAX_RETRIES	5
+
+/*
+ * Address to scan
+ * Address is fully defined internally and cannot be changed.
+ */
+
+static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
+
+/*
+ * The W83L785TS-S registers
+ * Manufacturer ID is 0x5CA3 for Winbond.
+ */
+
+#define W83L785TS_REG_MAN_ID1		0x4D
+#define W83L785TS_REG_MAN_ID2		0x4C
+#define W83L785TS_REG_CHIP_ID		0x4E
+#define W83L785TS_REG_CONFIG		0x40
+#define W83L785TS_REG_TYPE		0x52
+#define W83L785TS_REG_TEMP		0x27
+#define W83L785TS_REG_TEMP_OVER		0x53 /* not sure about this one */
+
+/*
+ * Conversions
+ * The W83L785TS-S uses signed 8-bit values.
+ */
+
+#define TEMP_FROM_REG(val)	((val) * 1000)
+
+/*
+ * Functions declaration
+ */
+
+static int w83l785ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id);
+static int w83l785ts_detect(struct i2c_client *client,
+			    struct i2c_board_info *info);
+static int w83l785ts_remove(struct i2c_client *client);
+static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
+static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id w83l785ts_id[] = {
+	{ "w83l785ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
+
+static struct i2c_driver w83l785ts_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "w83l785ts",
+	},
+	.probe		= w83l785ts_probe,
+	.remove		= w83l785ts_remove,
+	.id_table	= w83l785ts_id,
+	.detect		= w83l785ts_detect,
+	.address_list	= normal_i2c,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct w83l785ts_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	s8 temp[2]; /* 0: input, 1: critical limit */
+};
+
+/*
+ * Sysfs stuff
+ */
+
+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 w83l785ts_data *data = w83l785ts_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
+
+/*
+ * Real code
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83l785ts_detect(struct i2c_client *client,
+			    struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u16 man_id;
+	u8 chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* detection */
+	if ((w83l785ts_read_value(client, W83L785TS_REG_CONFIG, 0) & 0x80)
+	 || (w83l785ts_read_value(client, W83L785TS_REG_TYPE, 0) & 0xFC)) {
+		dev_dbg(&adapter->dev,
+			"W83L785TS-S detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	/* Identification */
+	man_id = (w83l785ts_read_value(client, W83L785TS_REG_MAN_ID1, 0) << 8)
+	       + w83l785ts_read_value(client, W83L785TS_REG_MAN_ID2, 0);
+	chip_id = w83l785ts_read_value(client, W83L785TS_REG_CHIP_ID, 0);
+
+	if (man_id != 0x5CA3		/* Winbond */
+	 || chip_id != 0x70) {		/* W83L785TS-S */
+		dev_dbg(&adapter->dev,
+			"Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
+			man_id, chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int w83l785ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct w83l785ts_data *data;
+	struct device *dev = &client->dev;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(struct w83l785ts_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the W83L785TS chip
+	 * Nothing yet, assume it is already started.
+	 */
+
+	err = device_create_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
+	if (err)
+		return err;
+
+	err = device_create_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
+	if (err)
+		goto exit_remove;
+
+	/* Register sysfs hooks */
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	device_remove_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
+	device_remove_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
+	return err;
+}
+
+static int w83l785ts_remove(struct i2c_client *client)
+{
+	struct w83l785ts_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	device_remove_file(&client->dev,
+			   &sensor_dev_attr_temp1_input.dev_attr);
+	device_remove_file(&client->dev,
+			   &sensor_dev_attr_temp1_max.dev_attr);
+
+	return 0;
+}
+
+static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
+{
+	int value, i;
+	struct device *dev;
+	const char *prefix;
+
+	/*
+	 * We might be called during detection, at which point the client
+	 * isn't yet fully initialized, so we can't use dev_dbg on it
+	 */
+	if (i2c_get_clientdata(client)) {
+		dev = &client->dev;
+		prefix = "";
+	} else {
+		dev = &client->adapter->dev;
+		prefix = "w83l785ts: ";
+	}
+
+	/*
+	 * Frequent read errors have been reported on Asus boards, so we
+	 * retry on read errors. If it still fails (unlikely), return the
+	 * default value requested by the caller.
+	 */
+	for (i = 1; i <= MAX_RETRIES; i++) {
+		value = i2c_smbus_read_byte_data(client, reg);
+		if (value >= 0) {
+			dev_dbg(dev, "%sRead 0x%02x from register 0x%02x.\n",
+				prefix, value, reg);
+			return value;
+		}
+		dev_dbg(dev, "%sRead failed, will retry in %d.\n", prefix, i);
+		msleep(i);
+	}
+
+	dev_err(dev, "%sCouldn't read value from register 0x%02x.\n", prefix,
+		reg);
+	return defval;
+}
+
+static struct w83l785ts_data *w83l785ts_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83l785ts_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) {
+		dev_dbg(&client->dev, "Updating w83l785ts data.\n");
+		data->temp[0] = w83l785ts_read_value(client,
+				W83L785TS_REG_TEMP, data->temp[0]);
+		data->temp[1] = w83l785ts_read_value(client,
+				W83L785TS_REG_TEMP_OVER, data->temp[1]);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+module_i2c_driver(w83l785ts_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("W83L785TS-S driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
new file mode 100644
index 0000000..3302996
--- /dev/null
+++ b/drivers/hwmon/w83l786ng.c
@@ -0,0 +1,778 @@
+/*
+ * w83l786ng.c - Linux kernel driver for hardware monitoring
+ * Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * Supports following chips:
+ *
+ * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+ * w83l786ng	3	2	2	2	0x7b	0x5ca3	yes	no
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+
+static bool reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+#define W83L786NG_REG_IN_MIN(nr)	(0x2C + (nr) * 2)
+#define W83L786NG_REG_IN_MAX(nr)	(0x2B + (nr) * 2)
+#define W83L786NG_REG_IN(nr)		((nr) + 0x20)
+
+#define W83L786NG_REG_FAN(nr)		((nr) + 0x28)
+#define W83L786NG_REG_FAN_MIN(nr)	((nr) + 0x3B)
+
+#define W83L786NG_REG_CONFIG		0x40
+#define W83L786NG_REG_ALARM1		0x41
+#define W83L786NG_REG_ALARM2		0x42
+#define W83L786NG_REG_GPIO_EN		0x47
+#define W83L786NG_REG_MAN_ID2		0x4C
+#define W83L786NG_REG_MAN_ID1		0x4D
+#define W83L786NG_REG_CHIP_ID		0x4E
+
+#define W83L786NG_REG_DIODE		0x53
+#define W83L786NG_REG_FAN_DIV		0x54
+#define W83L786NG_REG_FAN_CFG		0x80
+
+#define W83L786NG_REG_TOLERANCE		0x8D
+
+static const u8 W83L786NG_REG_TEMP[2][3] = {
+	{ 0x25,		/* TEMP 0 in DataSheet */
+	  0x35,		/* TEMP 0 Over in DataSheet */
+	  0x36 },	/* TEMP 0 Hyst in DataSheet */
+	{ 0x26,		/* TEMP 1 in DataSheet */
+	  0x37,		/* TEMP 1 Over in DataSheet */
+	  0x38 }	/* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83L786NG_PWM_MODE_SHIFT[] = {6, 7};
+static const u8 W83L786NG_PWM_ENABLE_SHIFT[] = {2, 4};
+
+/* FAN Duty Cycle, be used to control */
+static const u8 W83L786NG_REG_PWM[] = {0x81, 0x87};
+
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val, div)	((val) == 0   ? -1 : \
+				((val) == 255 ? 0 : \
+				1350000 / ((val) * (div))))
+
+/* for temp */
+#define TEMP_TO_REG(val)	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+						      : (val)) / 1000, 0, 0xff))
+#define TEMP_FROM_REG(val)	(((val) & 0x80 ? \
+				  (val) - 0x100 : (val)) * 1000)
+
+/*
+ * The analog voltage inputs have 8mV LSB. Since the sysfs output is
+ * in mV as would be measured on the chip input pin, need to just
+ * multiply/divide by 8 to translate from/to register values.
+ */
+#define IN_TO_REG(val)		(clamp_val((((val) + 4) / 8), 0, 255))
+#define IN_FROM_REG(val)	((val) * 8)
+
+#define DIV_FROM_REG(val)	(1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+	int i;
+	val = clamp_val(val, 1, 128) >> 1;
+	for (i = 0; i < 7; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return (u8)i;
+}
+
+struct w83l786ng_data {
+	struct i2c_client *client;
+	struct mutex update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	unsigned long last_nonvolatile;	/* In jiffies, last time we update the
+					 * nonvolatile registers */
+
+	u8 in[3];
+	u8 in_max[3];
+	u8 in_min[3];
+	u8 fan[2];
+	u8 fan_div[2];
+	u8 fan_min[2];
+	u8 temp_type[2];
+	u8 temp[2][3];
+	u8 pwm[2];
+	u8 pwm_mode[2];	/* 0->DC variable voltage
+			 * 1->PWM variable duty cycle */
+
+	u8 pwm_enable[2]; /* 1->manual
+			   * 2->thermal cruise (also called SmartFan I) */
+	u8 tolerance[2];
+};
+
+static u8
+w83l786ng_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static struct w83l786ng_data *w83l786ng_update_device(struct device *dev)
+{
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int i, j;
+	u8 reg_tmp, pwmcfg;
+
+	mutex_lock(&data->update_lock);
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		dev_dbg(&client->dev, "Updating w83l786ng data.\n");
+
+		/* Update the voltages measured value and limits */
+		for (i = 0; i < 3; i++) {
+			data->in[i] = w83l786ng_read_value(client,
+			    W83L786NG_REG_IN(i));
+			data->in_min[i] = w83l786ng_read_value(client,
+			    W83L786NG_REG_IN_MIN(i));
+			data->in_max[i] = w83l786ng_read_value(client,
+			    W83L786NG_REG_IN_MAX(i));
+		}
+
+		/* Update the fan counts and limits */
+		for (i = 0; i < 2; i++) {
+			data->fan[i] = w83l786ng_read_value(client,
+			    W83L786NG_REG_FAN(i));
+			data->fan_min[i] = w83l786ng_read_value(client,
+			    W83L786NG_REG_FAN_MIN(i));
+		}
+
+		/* Update the fan divisor */
+		reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
+		data->fan_div[0] = reg_tmp & 0x07;
+		data->fan_div[1] = (reg_tmp >> 4) & 0x07;
+
+		pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+		for (i = 0; i < 2; i++) {
+			data->pwm_mode[i] =
+			    ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1)
+			    ? 0 : 1;
+			data->pwm_enable[i] =
+			    ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 3) + 1;
+			data->pwm[i] =
+			    (w83l786ng_read_value(client, W83L786NG_REG_PWM[i])
+			     & 0x0f) * 0x11;
+		}
+
+
+		/* Update the temperature sensors */
+		for (i = 0; i < 2; i++) {
+			for (j = 0; j < 3; j++) {
+				data->temp[i][j] = w83l786ng_read_value(client,
+				    W83L786NG_REG_TEMP[i][j]);
+			}
+		}
+
+		/* Update Smart Fan I/II tolerance */
+		reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE);
+		data->tolerance[0] = reg_tmp & 0x0f;
+		data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+	   char *buf) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \
+}
+
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define store_in_reg(REG, reg) \
+static ssize_t \
+store_in_##reg(struct device *dev, struct device_attribute *attr, \
+	       const char *buf, size_t count) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct w83l786ng_data *data = dev_get_drvdata(dev); \
+	struct i2c_client *client = data->client; \
+	unsigned long val; \
+	int err = kstrtoul(buf, 10, &val); \
+	if (err) \
+		return err; \
+	mutex_lock(&data->update_lock); \
+	data->in_##reg[nr] = IN_TO_REG(val); \
+	w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \
+			      data->in_##reg[nr]); \
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+store_in_reg(MIN, min)
+store_in_reg(MAX, max)
+
+static struct sensor_device_attribute sda_in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+};
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			  char *buf) \
+{ \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+	return sprintf(buf, "%d\n", \
+		FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr),
+			      data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+	     char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = w83l786ng_update_device(dev);
+	return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+/*
+ * Note: we save and restore the fan minimum here, because its value is
+ * determined in part by the fan divisor.  This follows the principle of
+ * least surprise; the user doesn't expect the fan minimum to change just
+ * because the divisor changed.
+ */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+
+	unsigned long min;
+	u8 tmp_fan_div;
+	u8 fan_div_reg;
+	u8 keep_mask = 0;
+	u8 new_shift = 0;
+
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	/* Save fan_min */
+	mutex_lock(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+
+	data->fan_div[nr] = DIV_TO_REG(val);
+
+	switch (nr) {
+	case 0:
+		keep_mask = 0xf8;
+		new_shift = 0;
+		break;
+	case 1:
+		keep_mask = 0x8f;
+		new_shift = 4;
+		break;
+	}
+
+	fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV)
+					   & keep_mask;
+
+	tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask;
+
+	w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV,
+			      fan_div_reg | tmp_fan_div);
+
+	/* Restore fan_min */
+	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr),
+			      data->fan_min[nr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 1),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div,
+		    store_fan_div, 0),
+	SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div,
+		    store_fan_div, 1),
+};
+
+
+/* read/write the temperature, includes measured value and limits */
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83l786ng_data *data = w83l786ng_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr][index] = TEMP_TO_REG(val);
+	w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index],
+			      data->temp[nr][index]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+	SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+		      show_temp, store_temp, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
+		      show_temp, store_temp, 1, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		      show_temp, store_temp, 0, 2),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+		      show_temp, store_temp, 1, 2),
+};
+
+#define show_pwm_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			  char *buf) \
+{ \
+	struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+	int nr = to_sensor_dev_attr(attr)->index; \
+	return sprintf(buf, "%d\n", data->reg[nr]); \
+}
+
+show_pwm_reg(pwm_mode)
+show_pwm_reg(pwm_enable)
+show_pwm_reg(pwm)
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+	mutex_lock(&data->update_lock);
+	data->pwm_mode[nr] = val;
+	reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+	reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]);
+	if (!val)
+		reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr];
+	w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	val = clamp_val(val, 0, 255);
+	val = DIV_ROUND_CLOSEST(val, 0x11);
+
+	mutex_lock(&data->update_lock);
+	data->pwm[nr] = val * 0x11;
+	val |= w83l786ng_read_value(client, W83L786NG_REG_PWM[nr]) & 0xf0;
+	w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 reg;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (!val || val > 2)  /* only modes 1 and 2 are supported */
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+	data->pwm_enable[nr] = val;
+	reg &= ~(0x03 << W83L786NG_PWM_ENABLE_SHIFT[nr]);
+	reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr];
+	w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+};
+
+static struct sensor_device_attribute sda_pwm_mode[] = {
+	SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 0),
+	SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+		    store_pwm_mode, 1),
+};
+
+static struct sensor_device_attribute sda_pwm_enable[] = {
+	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 0),
+	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+		    store_pwm_enable, 1),
+};
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = w83l786ng_update_device(dev);
+	return sprintf(buf, "%ld\n", (long)data->tolerance[nr]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct w83l786ng_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u8 tol_tmp, tol_mask;
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	tol_mask = w83l786ng_read_value(client,
+	    W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0);
+	tol_tmp = clamp_val(val, 0, 15);
+	tol_tmp &= 0x0f;
+	data->tolerance[nr] = tol_tmp;
+	if (nr == 1)
+		tol_tmp <<= 4;
+
+	w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE,
+			      tol_mask | tol_tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_tolerance[] = {
+	SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO,
+		    show_tolerance, store_tolerance, 0),
+	SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO,
+		    show_tolerance, store_tolerance, 1),
+};
+
+
+#define IN_UNIT_ATTRS(X)	\
+	&sda_in_input[X].dev_attr.attr,		\
+	&sda_in_min[X].dev_attr.attr,		\
+	&sda_in_max[X].dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X)	\
+	&sda_fan_input[X].dev_attr.attr,	\
+	&sda_fan_min[X].dev_attr.attr,		\
+	&sda_fan_div[X].dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X)	\
+	&sda_temp_input[X].dev_attr.attr,	\
+	&sda_temp_max[X].dev_attr.attr,		\
+	&sda_temp_max_hyst[X].dev_attr.attr
+
+#define PWM_UNIT_ATTRS(X)	\
+	&sda_pwm[X].dev_attr.attr,		\
+	&sda_pwm_mode[X].dev_attr.attr,		\
+	&sda_pwm_enable[X].dev_attr.attr
+
+#define TOLERANCE_UNIT_ATTRS(X)	\
+	&sda_tolerance[X].dev_attr.attr
+
+static struct attribute *w83l786ng_attrs[] = {
+	IN_UNIT_ATTRS(0),
+	IN_UNIT_ATTRS(1),
+	IN_UNIT_ATTRS(2),
+	FAN_UNIT_ATTRS(0),
+	FAN_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(0),
+	TEMP_UNIT_ATTRS(1),
+	PWM_UNIT_ATTRS(0),
+	PWM_UNIT_ATTRS(1),
+	TOLERANCE_UNIT_ATTRS(0),
+	TOLERANCE_UNIT_ATTRS(1),
+	NULL
+};
+
+ATTRIBUTE_GROUPS(w83l786ng);
+
+static int
+w83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	u16 man_id;
+	u8 chip_id;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	/* Detection */
+	if ((w83l786ng_read_value(client, W83L786NG_REG_CONFIG) & 0x80)) {
+		dev_dbg(&adapter->dev, "W83L786NG detection failed at 0x%02x\n",
+			client->addr);
+		return -ENODEV;
+	}
+
+	/* Identification */
+	man_id = (w83l786ng_read_value(client, W83L786NG_REG_MAN_ID1) << 8) +
+		 w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2);
+	chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID);
+
+	if (man_id != 0x5CA3 ||		/* Winbond */
+	    chip_id != 0x80) {		/* W83L786NG */
+		dev_dbg(&adapter->dev,
+			"Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
+			man_id, chip_id);
+		return -ENODEV;
+	}
+
+	strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static void w83l786ng_init_client(struct i2c_client *client)
+{
+	u8 tmp;
+
+	if (reset)
+		w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80);
+
+	/* Start monitoring */
+	tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG);
+	if (!(tmp & 0x01))
+		w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01);
+}
+
+static int
+w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct w83l786ng_data *data;
+	struct device *hwmon_dev;
+	int i;
+	u8 reg_tmp;
+
+	data = devm_kzalloc(dev, sizeof(struct w83l786ng_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the chip */
+	w83l786ng_init_client(client);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 2; i++) {
+		data->fan_min[i] = w83l786ng_read_value(client,
+		    W83L786NG_REG_FAN_MIN(i));
+	}
+
+	/* Update the fan divisor */
+	reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
+	data->fan_div[0] = reg_tmp & 0x07;
+	data->fan_div[1] = (reg_tmp >> 4) & 0x07;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+							   data,
+							   w83l786ng_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id w83l786ng_id[] = {
+	{ "w83l786ng", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
+
+static struct i2c_driver w83l786ng_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		   .name = "w83l786ng",
+	},
+	.probe		= w83l786ng_probe,
+	.id_table	= w83l786ng_id,
+	.detect		= w83l786ng_detect,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(w83l786ng_driver);
+
+MODULE_AUTHOR("Kevin Lo");
+MODULE_DESCRIPTION("w83l786ng driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c
new file mode 100644
index 0000000..a16cce7
--- /dev/null
+++ b/drivers/hwmon/wm831x-hwmon.c
@@ -0,0 +1,165 @@
+/*
+ * drivers/hwmon/wm831x-hwmon.c - Wolfson Microelectronics WM831x PMIC
+ *                                hardware monitoring features.
+ *
+ * Copyright (C) 2009 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/auxadc.h>
+
+static const char * const input_names[] = {
+	[WM831X_AUX_SYSVDD]    = "SYSVDD",
+	[WM831X_AUX_USB]       = "USB",
+	[WM831X_AUX_BKUP_BATT] = "Backup battery",
+	[WM831X_AUX_BATT]      = "Battery",
+	[WM831X_AUX_WALL]      = "WALL",
+	[WM831X_AUX_CHIP_TEMP] = "PMIC",
+	[WM831X_AUX_BATT_TEMP] = "Battery",
+};
+
+static ssize_t show_voltage(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct wm831x *wm831x = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(attr)->index;
+	int ret;
+
+	ret = wm831x_auxadc_read_uv(wm831x, channel);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret, 1000));
+}
+
+static ssize_t show_chip_temp(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct wm831x *wm831x = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(attr)->index;
+	int ret;
+
+	ret = wm831x_auxadc_read(wm831x, channel);
+	if (ret < 0)
+		return ret;
+
+	/* Degrees celsius = (512.18-ret) / 1.0983 */
+	ret = 512180 - (ret * 1000);
+	ret = DIV_ROUND_CLOSEST(ret * 10000, 10983);
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	int channel = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", input_names[channel]);
+}
+
+#define WM831X_VOLTAGE(id, name) \
+	static SENSOR_DEVICE_ATTR(in##id##_input, S_IRUGO, show_voltage, \
+				  NULL, name)
+
+#define WM831X_NAMED_VOLTAGE(id, name) \
+	WM831X_VOLTAGE(id, name); \
+	static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label,	\
+				  NULL, name)
+
+WM831X_VOLTAGE(0, WM831X_AUX_AUX1);
+WM831X_VOLTAGE(1, WM831X_AUX_AUX2);
+WM831X_VOLTAGE(2, WM831X_AUX_AUX3);
+WM831X_VOLTAGE(3, WM831X_AUX_AUX4);
+
+WM831X_NAMED_VOLTAGE(4, WM831X_AUX_SYSVDD);
+WM831X_NAMED_VOLTAGE(5, WM831X_AUX_USB);
+WM831X_NAMED_VOLTAGE(6, WM831X_AUX_BATT);
+WM831X_NAMED_VOLTAGE(7, WM831X_AUX_WALL);
+WM831X_NAMED_VOLTAGE(8, WM831X_AUX_BKUP_BATT);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_chip_temp, NULL,
+			  WM831X_AUX_CHIP_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
+			  WM831X_AUX_CHIP_TEMP);
+/*
+ * Report as a voltage since conversion depends on external components
+ * and that's what the ABI wants.
+ */
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_voltage, NULL,
+			  WM831X_AUX_BATT_TEMP);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
+			  WM831X_AUX_BATT_TEMP);
+
+static struct attribute *wm831x_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_label.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_label.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in7_label.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in8_label.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+
+	NULL
+};
+
+ATTRIBUTE_GROUPS(wm831x);
+
+static int wm831x_hwmon_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct device *hwmon_dev;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "wm831x",
+							   wm831x,
+							   wm831x_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver wm831x_hwmon_driver = {
+	.probe = wm831x_hwmon_probe,
+	.driver = {
+		.name = "wm831x-hwmon",
+	},
+};
+
+module_platform_driver(wm831x_hwmon_driver);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM831x Hardware Monitoring");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-hwmon");
diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c
new file mode 100644
index 0000000..31af438
--- /dev/null
+++ b/drivers/hwmon/wm8350-hwmon.c
@@ -0,0 +1,104 @@
+/*
+ * drivers/hwmon/wm8350-hwmon.c - Wolfson Microelectronics WM8350 PMIC
+ *                                  hardware monitoring features.
+ *
+ * Copyright (C) 2009 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/comparator.h>
+
+static const char * const input_names[] = {
+	[WM8350_AUXADC_USB]  = "USB",
+	[WM8350_AUXADC_LINE] = "Line",
+	[WM8350_AUXADC_BATT] = "Battery",
+};
+
+static ssize_t show_voltage(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct wm8350 *wm8350 = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(attr)->index;
+	int val;
+
+	val = wm8350_read_auxadc(wm8350, channel, 0, 0) * WM8350_AUX_COEFF;
+	val = DIV_ROUND_CLOSEST(val, 1000);
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	int channel = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", input_names[channel]);
+}
+
+#define WM8350_NAMED_VOLTAGE(id, name) \
+	static SENSOR_DEVICE_ATTR(in##id##_input, S_IRUGO, show_voltage,\
+				  NULL, name);		\
+	static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label,	\
+				  NULL, name)
+
+WM8350_NAMED_VOLTAGE(0, WM8350_AUXADC_USB);
+WM8350_NAMED_VOLTAGE(1, WM8350_AUXADC_BATT);
+WM8350_NAMED_VOLTAGE(2, WM8350_AUXADC_LINE);
+
+static struct attribute *wm8350_attrs[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(wm8350);
+
+static int wm8350_hwmon_probe(struct platform_device *pdev)
+{
+	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+	struct device *hwmon_dev;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "wm8350",
+							   wm8350,
+							   wm8350_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver wm8350_hwmon_driver = {
+	.probe = wm8350_hwmon_probe,
+	.driver = {
+		.name = "wm8350-hwmon",
+	},
+};
+
+module_platform_driver(wm8350_hwmon_driver);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8350 Hardware Monitoring");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-hwmon");