<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.linux.drivers.sensors">
    <title>gmane.linux.drivers.sensors</title>
    <link>http://blog.gmane.org/gmane.linux.drivers.sensors</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29722"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29717"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29716"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29714"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29712"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29711"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29704"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29702"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29701"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29699"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29696"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29694"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29687"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29672"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29657"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29656"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29652"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29636"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29635"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.drivers.sensors/29624"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29722">
    <title>Supermicro X8DTN config file</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29722</link>
    <description>&lt;pre&gt;Yo lm-sesors!

See below for a working sensors3.conf file for the Supermicro X8DTN
motherboard.

How do I get it posted on the wiki for others to use?

RGDS
GARY
---------------------------------------------------------------------------
Gary E. Miller Rellim 109 NW Wilmington Ave., Suite E, Bend, OR 97701
gem&amp;lt; at &amp;gt;rellim.com  Tel:+1(541)382-8588

# /etc/sensors.d/X8DTN
# settings for the supermicro X8DTN
# originally written by Gary E. Miller &amp;lt;gem&amp;lt; at &amp;gt;rellim.com&amp;gt;
# use at your own risk !
# Date: 25 May 2012

# Here's the info as supplied by Supermicro:

#
# Bus Type = ISAIO/SMBus
# One W83795AG
# 
# Windbond W83795AG, Slave Address=0x2f (0x5E in 8-Bit format)
# =============================================================
# Fan1 Fan Speed, Offset 0x2eRPM = 84375/Data
# Fan2 Fan Speed, Offset 0x2fRPM = 84375/Data
# Fan3 Fan Speed, Offset 0x30RPM = 84375/Data
# Fan4 Fan Speed, Offset 0x31RPM = 84375/Data
# Fan5 Fan Speed, Offset 0x32RPM = 84375/Data
# Fan6 Fan Speed, Offset 0x33RPM = 84375/Data
# Fan7 Fan Speed, Offset 0x34RPM = 84375/Data
# Fan8 Fan Speed, Offset 0x35RPM = 84375/Data
# CPU1 Voltage, Offset 0x10Voltage = Data* 0.008
# CPU2 Voltage, Offset 0x11Voltage = Data* 0.008
# +1.5V Voltage, Offset 0x12Voltage = Data* 0.008
# +5V Voltage, Offset 0x13Voltage = Data* 0.008 * (40/10)
# +12V Voltage, Offset 0x14Voltage = Data* 0.008/ (10./66.2)
# +5VSB Voltage, Offset 0x15Voltage = Data* 0.008 * (40/10)
# +3.3V Voltage, Offset 0x1cVoltage = Data* 0.024
# +3.3VSB Voltage, Offset 0x1dVoltage = Data* 0.024
# Battery Voltage, Offset 0x1eVoltage = Data* 0.024
# CPU1 Temperature, Offset 0x27Temperature = Data
# CPU2 Temperature, Offset 0x26Temperature = Data
# System Temperature, Offset 0x1fTemperature = Data
# Chassis Intrusion, Bank 0, Offset 0x46, BitMask 0x401 = Bad, 0 = Good
# (Clear Bit: Bank 0, Offset 0x4d, BitMask 0x80)
# 
# 
# Power Supply Failure, GP11(From W83627HF)1 = Good, 0 = Bad
 
chip "w83627hf-isa-0a00"
    # I'm not sure which is GP11, so I turned off everything.
    ignore in0
    ignore in1
    ignore in2
    ignore in3
    ignore in4
    ignore in5
    ignore in6
    ignore in7
    ignore in8
    ignore cpu0_vid
    ignore fan1
    ignore fan2
    ignore fan3
    ignore temp1
    ignore temp2
    ignore temp3
 
bus "i2c-0" "SMBus I801 adapter at 0400"

chip "w83795adg-i2c-0-2f"

# Voltages ; note that in the table above, the .008 and .024 factors are
# already computed in the driver...

    label in0 "CPU1"
    label in1 "CPU2"
    label in2 "+1.5V"
    label in3 "+5V"
    label in4 "+12V"
    label in5 "5VSB"
    label in11 "Vtt"
    label in12 "+3.3V"
    label in13 "3VSB"
    label in14 "Vbat"

    compute in3 &amp;lt; at &amp;gt;*4, &amp;lt; at &amp;gt;/4
    compute in4 &amp;lt; at &amp;gt;*6.62, &amp;lt; at &amp;gt;/6.62
    compute in5 &amp;lt; at &amp;gt;*4, &amp;lt; at &amp;gt;/4
    compute in6 &amp;lt; at &amp;gt;*3, &amp;lt; at &amp;gt;/3

    label temp3 "unused"
    label temp4 "unused"
    label temp5 "mobo"
    label temp7 "CPU1"
    label temp8 "CPU2"

    ignore in6
    ignore in7
    ignore in11
    ignore temp3
    ignore temp4
    ignore fan4
    ignore fan5
    ignore fan6
    ignore fan7
    ignore fan8

    set in0_min  0.82
    set in0_max  1.35
    set in1_min  0.82
    set in1_max  1.35
    set in12_min  3.3 * 0.90
    set in12_max  3.3 * 1.10
    set in13_min  3.3 * 0.90
    set in13_max  3.3 * 1.10
    set in14_min  3.0 * 0.90
    set in14_max  3.3 * 1.10


_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Gary E. Miller</dc:creator>
    <dc:date>2012-05-25T18:10:56</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29717">
    <title>rocky hu与您共享了照片</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29717</link>
    <description>&lt;pre&gt;If you are anxious for not find good supplier ? please contact us, we will  
offer you best service.
we are serious business person.

wholesale Louis Vuitton, Gucci, Fendi, Prada, Hermes, Chloe, Balenciage,  
Chanel, Coach, Jimmy choo, Juicy etc.

Such as Handbags, Wallets, T-shirt, sport shoes, Jerseys,Jackets,  
Jeans,Jewelry, hoody, Sunglasses, Belts, Bikini, Boots, the north face  
jacket ect

Website: www.sobagssoyou.com


Payment: Paypal, western union,Money Gram

Shipping: 5-6 business days
  more order, more discount

Hope to do business with you.
Email:cnwholesalelist&amp;lt; at &amp;gt;hotmail.com
_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>rocky hu</dc:creator>
    <dc:date>2012-05-24T16:36:16</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29716">
    <title>[patch] watchdog: sch56xx-common: set correct bits inregister()</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29716</link>
    <description>&lt;pre&gt;WDOG_NO_WAY_OUT (3) and WDOG_ACTIVE (0) are the bit numbers, not a mask.
So "data-&amp;gt;wddev.status |= WDOG_ACTIVE;" was intended to set bit zero but
it is a no-op.

Signed-off-by: Dan Carpenter &amp;lt;dan.carpenter&amp;lt; at &amp;gt;oracle.com&amp;gt;

diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 839087c..4380f5d 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -464,9 +464,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
 data-&amp;gt;wddev.min_timeout = 1;
 data-&amp;gt;wddev.max_timeout = 255 * 60;
 if (nowayout)
-data-&amp;gt;wddev.status |= WDOG_NO_WAY_OUT;
+set_bit(WDOG_NO_WAY_OUT, &amp;amp;data-&amp;gt;wddev.status);
 if (output_enable &amp;amp; SCH56XX_WDOG_OUTPUT_ENABLE)
-data-&amp;gt;wddev.status |= WDOG_ACTIVE;
+set_bit(WDOG_ACTIVE, &amp;amp;data-&amp;gt;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) -&amp;gt;

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

&lt;/pre&gt;</description>
    <dc:creator>Dan Carpenter</dc:creator>
    <dc:date>2012-05-24T15:58:02</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29714">
    <title>Nuvoton NCT6776D - AsRock</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29714</link>
    <description>&lt;pre&gt;Hello to all,

Have a new card *AsRock B75 Pro 3 M* yesterday.

This card uses a new chip *Nuvoton NCT6776D.*

Can we have full support for Lm-Sensors ?

For now only the temperature of my i3 2100 are displayed.


Thank you for your help.

Clem from South France
_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>clement clem</dc:creator>
    <dc:date>2012-05-23T16:25:06</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29712">
    <title>lavoriamo insieme</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29712</link>
    <description>&lt;pre&gt;Salve,

vorrei cogliere questa occasione per presentarmi.
Il mio nome &amp;amp;egrave; Lucia Casati e sono la responsabile di Italy-SEO.

Lavoro al fianco di numerosi siti internet. Gestisco il loro SEO
in base alle particolarit&amp;amp;agrave; dei maggiori motori di ricerca on line,
tra cui Google, Bing e Yahoo.

Lavorando al sito web di uno dei miei partner lavorativi,
ho incrociato lists.lm-sensors.org
Sono convinta di poter esserle utile per incrementare il traffico,
la visibilit&amp;amp;agrave; e il Page Rank del suo sito.

Se interessato, sarei pi&amp;amp;ugrave; che felice di elaborare meglio
i dettagli della mia proposta di assistenza.

Le auguro una buona giornata,

Lucia Casati
Italyseo.com

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Lucia Casati</dc:creator>
    <dc:date>2012-05-23T10:05:18</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29711">
    <title>ASUS Sabertooth Z77 / nct6775.ko report</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29711</link>
    <description>&lt;pre&gt;Hi,

Got a new ASUS Sabertooth Z77 mobo recently and found out that lm-sensors didn't support
anything but the core temperatures and also a couple ones from the
'acpitz-virtual-0' device. Trying the trunk version of sensors-detect didn't help.

I then searched and finally found the shiny new 'nct6775' driver. Compiled and loaded it successfully (linux 3.4.0 x86_64):

[ 1082.377370] nct6775: Found NCT6779D chip at 0x290

Here's how my sensors output looking now (lm-sensors 3.3.2 from Debian wheezy/sid):

acpitz-virtual-0
Adapter: Virtual device
temp1:        +27.8°C  (crit = +106.0°C)
temp2:        +29.8°C  (crit = +106.0°C)

coretemp-isa-0000
Adapter: ISA adapter
Physical id 0:  +45.0°C  (high = +85.0°C, crit = +105.0°C)
Core 0:         +44.0°C  (high = +85.0°C, crit = +105.0°C)
Core 1:         +45.0°C  (high = +85.0°C, crit = +105.0°C)
Core 2:         +43.0°C  (high = +85.0°C, crit = +105.0°C)
Core 3:         +43.0°C  (high = +85.0°C, crit = +105.0°C)

nct6779-isa-0290
Adapter: ISA adapter
in0:                    +1.00 V  (min =  +0.00 V, max =  +1.74 V)
in1:                    +1.03 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in2:                    +3.42 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in3:                    +3.42 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in4:                    +1.02 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in5:                    +2.04 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in6:                    +1.49 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in7:                    +3.41 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in8:                    +3.36 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in9:                    +1.06 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in10:                   +1.49 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in11:                   +1.49 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in12:                   +0.25 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in13:                   +0.18 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in14:                   +1.49 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
fan1:                     0 RPM  (min =    0 RPM)
fan2:                  1142 RPM  (min =    0 RPM)
fan3:                  1011 RPM  (min =    0 RPM)
fan4:                   922 RPM  (min =    0 RPM)
fan5:                     0 RPM  (min =    0 RPM)
SYSTIN:                 +36.0°C  (high =  +0.0°C, hyst =  +0.0°C)  ALARM  sensor = thermistor
CPUTIN:                  +0.5°C  (high = +80.0°C, hyst = +75.0°C)  sensor = thermistor
AUXTIN0:                 +0.0°C    sensor = thermistor
AUXTIN1:                 +0.0°C    sensor = thermistor
AUXTIN2:                 +0.0°C    sensor = thermistor
AUXTIN3:                 +0.0°C    sensor = thermistor
PCH_CHIP_CPU_MAX_TEMP:   +0.0°C
PCH_CHIP_TEMP:           +0.0°C
PCH_CPU_TEMP:            +0.0°C
PCH_MCH_TEMP:            +0.0°C
cpu0_vid:              +0.000 V
intrusion0:            ALARM
intrusion1:            ALARM

Here's my thoughts:

- only 5 fans are shown whereas the mobo has 8 fan connectors (two of which are 3-pin, the rest are 4-pin);
- this board has a lot of temperature sensors (the windows asus monitoring utility shows around 8 or 9 of them I think), but only the SYSTIN seems to be reported correctly by this driver, the rest are zero;
- cpu0_vid has zero value as well;
- min/max values are zero for some of the sensors and the ALARM status is reported erroneously there;
- fan control *does* work via the /sys/devices/platform/nct6775.656/pwm* interface, both in PWM and DC control modes; I can reduce their speed and fully stop them.

What do you guys think of this? My current sensors-detect output is in the attachment and is also available at http://pastebin.com/BUs8e0sn. I also tried the 'lm75' and 'ds1621' drivers that it suggested, but that didn't change the output of sensors and there weren't any messages in dmesg when I loaded them.

I will gladly present any additional info that might help to debug the issue or improve the
driver.

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Dmitriy Pinchukov</dc:creator>
    <dc:date>2012-05-23T09:37:30</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29704">
    <title>ASRock 970 Extreme3</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29704</link>
    <description>&lt;pre&gt;I use the nct6776-isa-0290
Adapter: ISA adapter

I have 3 fans:
1. The CPU fan (about 3300 RPM)
2. The rear case fan (about 1050 RPM)
3. The front case fan (about 1350 RPM)

Do the fans in Power Supplies typically get monitored?

I have 6 fan connectors:
1. Chassis fan connector (#12 on the motherboard)
2. Chassis fan connector (#15 on the motherboard)
3. Chassis fan connector (#2 on the motherboard)
1. CPU fan connector (#6 on the motherboard)
2. CPU fan connector (#5 on the motherboard)
1. Power fan connector (#10 on the motherboard)

Maybe someone can see a pattern.

1. I plugged the rear case fan in #12
fan1 was 1060 RPM (the rear case fan probably)
fan2 was 3300 RPM (the CPU  fan probably)
other fans reported 0 RPMs

2. I plugged the rear case fan in #2
all fans reported 0 RPM
other fans reported 0 RPMs

3. I plugged the rear case fan in #12 and the front case fan in #15.
fan1 was 1053 RPM (the rear case fan probably)
fan2 was 3316 (the CPU fan probably)
other fans reported 0 RPMs

4. I plugged the rear case fan in #10 and the front case fan in #12.
fan1 was 1384 (the front case fan probably)
other fans reported 0 RPMs

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

&lt;/pre&gt;</description>
    <dc:creator>James</dc:creator>
    <dc:date>2012-05-21T13:45:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29702">
    <title>[PATCH] hwmon: Driver for Nuvoton NCT6775F, NCT6776F,and NCT6779D</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29702</link>
    <description>&lt;pre&gt;This driver will replace the w83627ehf driver for NCT6775F and NCT6776F,
and provides support for NCT6779D.

Signed-off-by: Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
---

Successfully tested on all supported chips. Time to submit for a first round of
reviews.

A new driver was chosen instead of adding support for NCT6779D to the w83627ehf
driver, since the amount of conditional code was getting too large to manage.
Also, with a new driver it was easier to implement additional fan control
support.

The driver implements a number of non-standard sysfs attributes for fan control.

TODO: Update Documentation/hwmon/nct6775 to list all supported sysfs attributes
(after we have an agreement about the non-standard attributes).

 Documentation/hwmon/nct6775 |  138 ++
 drivers/hwmon/Kconfig       |   13 +
 drivers/hwmon/Makefile      |    1 +
 drivers/hwmon/nct6775.c     | 3832 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 3984 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/hwmon/nct6775
 create mode 100644 drivers/hwmon/nct6775.c

diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775
new file mode 100644
index 0000000..c1e4868
--- /dev/null
+++ b/Documentation/hwmon/nct6775
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,138 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+Note
+====
+
+This driver supercedes the NCT6775F and NCT6776F support in the W83627EHF
+driver.
+
+Kernel driver NCT6775
+=======================
+
+Supported chips:
+  * Nuvoton NCT6775F/W83667HG-I
+    Prefix: 'nct6775'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6776F
+    Prefix: 'nct6776'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6779D
+    Prefix: 'nct6779'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+
+Authors:
+        Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
+
+Description
+-----------
+
+This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D
+super I/O chips. We will refer to them collectively as Nuvoton chips.
+
+The chips implement up to 8 temperature sensors depending on the chip type and
+configuration. Temperatures used to control fan speed are reported separately.
+There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
+one VID, alarms with beep warnings (control unimplemented), and some automatic
+fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on all chips are configurable. temp4 and higher
+attributes are only reported if its temperature source differs from the
+temperature sources of the already reported temperature sensors.
+The configured source for each of the temperature sensors is provided
+in tempX_label.
+
+Temperatures are measured in degrees Celsius and measurement resolution is
+either 1 degC or 0.5 degC, depending on the temperature source and
+configuration. An alarm is triggered when the temperature gets higher than
+the high limit; it stays on until the temperature falls below the hysteresis
+value. Alarms are only supported for temp1, temp2, and temp3.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
+128) to give the readings more range or accuracy. The driver sets the most
+suitable fan divisor itself. Some fans might not be present because they
+share pins with other functions.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+The driver supports automatic fan control mode known as Thermal Cruise.
+In this mode, the chip attempts to keep the measured temperature in a
+predefined temperature range. If the temperature goes out of range, fan
+is driven slower/faster to reach the predefined range again.
+
+The mode works for fan1-fan5.
+
+The temperature source used to control pwm1..pwm5 can be configured with
+pwm[1..5]_temp_sel and pwm[1..5]_weight_temp_sel. The value reported and
+configured with those attributes is the temperature sensor attribute index.
+For example, to map the source of temp1_input to pwm1_temp_sel, write 1
+into the pwm1_temp_sel attribute.
+
+sysfs attributes
+----------------
+
+name - this is a standard hwmon device entry, it contains the name of
+       the device (see the prefix in the list of supported devices at
+       the top of this file)
+
+pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
+   0 (stop) to 255 (full)
+
+pwm[1-5]_enable - this file controls mode of fan/temperature control:
+* 0 Fan control disabled (fans set to maximum speed)
+* 1 Manual mode, write to pwm file any value 0-255 (full speed)
+* 2 "Thermal Cruise" mode
+* 3 "Fan Speed Cruise" mode
+* 4 "Smart Fan III" mode (NCT6775F only)
+* 5 "Smart Fan IV" mode
+
+pwm[1-5]_mode - controls if output is PWM or DC level
+        * 0 DC output (0 - 12v)
+        * 1 PWM output
+
+Thermal Cruise mode
+-------------------
+
+If the temperature is in the range defined by:
+
+pwm[1-5]_target Target temperature, unit millidegree Celsius
+(range 0 - 127000)
+pwm[1-5]_auto_temp1_hyst
+Hysteresis, unit millidegree Celsius
+Hysteresis value is relative to pwm[1-5]_auto_temp1.
+
+there are no changes to fan speed. Once the temperature leaves the interval,
+fan speed increases (temp is higher) or decreases if lower than desired,
+using the following steps and times.
+
+pwm[1-5]_start_outputfan pwm start value (range 1 - 255), to start fan
+when the temperature is above defined range.
+pwm[1-5]_stop_outputfan pwm (range 1 - 255) to stop fan.
+pwm[1-5]_step_up_timemilliseconds [ms] before fan speed is increased
+pwm[1-5]_step_down_timemilliseconds [ms] before fan speed is decreased
+pwm[1-5]_stop_timehow many milliseconds [ms] must elapse to switch
+                      corresponding fan off. (when the temperature was below
+                      defined range).
+
+Speed Cruise mode
+-----------------
+
+This modes tries to keep the fan speed constant.
+Untested; use at your own risk.
+
+
+Usage Notes
+-----------
+
+On various ASUS boards with NCT6776F, it appears that CPUTIN is not really
+connected to anything and floats, or that it is connected to some non-standard
+temperature measurement device. As a result, the temperature reported on CPUTIN
+will not reflect a usable value. It often reports unreasonablyy high
+temperatures, and in some cases the reported temperature declines if the actual
+temperature increases (similar to the raw PECI temperature value - see PECI
+specification for details). CPUTIN should therefore be be ignored on ASUS
+boards. The CPU temperature on ASUS boards is reported from PECI 0.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 1c7bbd4..542b73e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -824,6 +824,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config SENSORS_MCP3021
   This driver can also be built as a module.  If so, the module
   will be called mcp3021.
 
+config SENSORS_NCT6775
+tristate "Nuvoton NCT6775F, NCT6776F, NCT6779D"
+depends on !PPC &amp;amp;&amp;amp; EXPERIMENTAL
+select HWMON_VID
+help
+  If you say yes here you get support for the hardware monitoring
+  functionality of the Nuvoton NCT6775F, NCT6776F, and NCT6779D
+  Super-I/O chips. It 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_NTC_THERMISTOR
 tristate "NTC thermistor support"
 depends on EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e1eeac1..37e728f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -97,6 +97,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; obj-$(CONFIG_SENSORS_MAX6642)+= max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)+= max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)+= mcp3021.o
+obj-$(CONFIG_SENSORS_NCT6775)+= nct6775.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)+= ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)+= pc87427.o
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
new file mode 100644
index 0000000..f32346d
--- /dev/null
+++ b/drivers/hwmon/nct6775.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,3832 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * nct6775 - Driver for the hardware monitoring functionality of
+ *       Nuvoton NCT677x Super-I/O chips
+ *
+ * Copyright (C) 2012  Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
+ *
+ * Derived from w83627ehf driver
+ * Copyright (C) 2005-2011  Jean Delvare &amp;lt;khali&amp;lt; at &amp;gt;linux-fr.org&amp;gt;
+ * Copyright (C) 2006  Yuan Mu (Winbond),
+ *       Rudolf Marek &amp;lt;r.marek&amp;lt; at &amp;gt;assembler.cz&amp;gt;
+ *       David Hubbard &amp;lt;david.c.hubbard&amp;lt; at &amp;gt;gmail.com&amp;gt;
+ *       Daniel J Blueman &amp;lt;daniel.blueman&amp;lt; at &amp;gt;gmail.com&amp;gt;
+ * 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
+ * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
+ * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
+ * nct6779d    15      5       5       2+5    0xc560 0xc1    0x5ca3
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include &amp;lt;linux/module.h&amp;gt;
+#include &amp;lt;linux/init.h&amp;gt;
+#include &amp;lt;linux/slab.h&amp;gt;
+#include &amp;lt;linux/jiffies.h&amp;gt;
+#include &amp;lt;linux/platform_device.h&amp;gt;
+#include &amp;lt;linux/hwmon.h&amp;gt;
+#include &amp;lt;linux/hwmon-sysfs.h&amp;gt;
+#include &amp;lt;linux/hwmon-vid.h&amp;gt;
+#include &amp;lt;linux/err.h&amp;gt;
+#include &amp;lt;linux/mutex.h&amp;gt;
+#include &amp;lt;linux/acpi.h&amp;gt;
+#include &amp;lt;linux/io.h&amp;gt;
+#include "lm75.h"
+
+#define TESTING
+
+enum kinds { nct6775, nct6776, nct6779 };
+
+/* used to set data-&amp;gt;name = nct6775_device_names[data-&amp;gt;sio_kind] */
+static const char * const nct6775_device_names[] = {
+"nct6775",
+"nct6776",
+"nct6779",
+};
+
+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_ACPI0x0a
+#define NCT6775_LD_HWM0x0b
+#define NCT6775_LD_VID0x0d
+
+#define SIO_REG_LDSEL0x07/* Logical device select */
+#define SIO_REG_DEVID0x20/* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM100x2C/* GPIO3, GPIO4 selection */
+#define SIO_REG_ENABLE0x30/* Logical device enable */
+#define SIO_REG_ADDR0x60/* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL0xF0/* VID control */
+#define SIO_REG_VID_DATA0xF1/* VID data */
+
+#define SIO_NCT6775_ID0xb470
+#define SIO_NCT6776_ID0xc330
+#define SIO_NCT6779_ID0xc560
+#define SIO_ID_MASK0xFFF0
+
+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_OFFSET5
+#define IOREGION_LENGTH2
+#define ADDR_REG_OFFSET0
+#define DATA_REG_OFFSET1
+
+#define NCT6775_REG_BANK0x4E
+#define NCT6775_REG_CONFIG0x40
+
+/*
+ * 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
+ */
+
+/* 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
+};
+
+static const u16 NCT6779_REG_IN[] = {
+0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
+0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e
+};
+
+#define NCT6775_REG_VBAT0x5D
+#define NCT6775_REG_DIODE0x5E
+
+#define NCT6775_REG_FANDIV10x506
+#define NCT6775_REG_FANDIV20x507
+
+#define NCT6775_REG_CR_FAN_DEBOUNCE0xf0
+
+static const u16 NCT6775_REG_ALARM[6] = { 0x459, 0x45A, 0x45B };
+static const u16 NCT6779_REG_ALARM[6] = { 0x459, 0x45A, 0x45B, 0x568 };
+
+/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+
+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, 10, 23,/* fan1..fan5 */
+    -1, -1, -1,/* unused */
+    4, 5, 13, -1, -1, -1,/* temp1..temp6 */
+    12, -1 };/* intrusion0, intrusion1 */
+
+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 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 */
+
+#define FAN_ALARM_BASE16
+#define TEMP_ALARM_BASE24
+#define INTRUSION_ALARM_BASE30
+
+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 };
+
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+
+/* Advanced Fan control, some values are common for all fans */
+
+static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
+static const u16 NCT6779_REG_FAN_PULSES[]
+= { 0x644, 0x645, 0x646, 0x647, 0x648 };
+
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
+0x103, 0x203, 0x303, 0x803, 0x903 };
+static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
+0x104, 0x204, 0x304, 0x804, 0x904 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
+0x105, 0x205, 0x305, 0x805, 0x905 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[]
+= { 0x106, 0x206, 0x306, 0x806, 0x906 };
+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 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
+static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
+
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
+
+static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+
+static const u16 NCT6779_REG_TOLERANCE_H[]
+= { 0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+
+static const u16 NCT6775_REG_TEMP[]
+= { 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
+static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
+
+static const u16 NCT6775_REG_TEMP_CONFIG[]
+= { 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[]
+= { 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[]
+= { 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
+
+static const u16 NCT6779_REG_TEMP_HYST[]
+= { 0x3a, 0x153, 0, 0, 0, 0 };
+static const u16 NCT6779_REG_TEMP_OVER[]
+= { 0x39, 0x155, 0, 0, 0, 0 };
+
+static const u16 NCT6775_REG_TEMP_SOURCE[]
+= { 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
+
+static const u16 NCT6775_REG_TEMP_SEL[]
+= { 0x100, 0x200, 0x300, 0x800, 0x900 };
+
+static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[]
+= { 0x139, 0x239, 0x339, 0x839, 0x939 };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[]
+= { 0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[]
+= { 0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[]
+= { 0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[]
+= { 0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+
+static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[]
+= { 0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+
+static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
+
+static const u16 NCT6779_REG_TEMP_OFFSET[]
+= { 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+
+static const u16 NCT6776_REG_TEMP_CONFIG[11]
+= { 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
+
+static const u16 NCT6779_REG_TEMP_CONFIG[11] = { 0x18, 0x152 };
+
+static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
+
+static const u16 NCT6775_REG_AUTO_TEMP[]
+= { 0x121, 0x221, 0x321, 0x821, 0x921 };
+static const u16 NCT6775_REG_AUTO_PWM[]
+= { 0x127, 0x227, 0x327, 0x827, 0x927 };
+
+#define NCT6775_AUTO_TEMP(data, nr, p)((data)-&amp;gt;REG_AUTO_TEMP[nr] + (p))
+#define NCT6775_AUTO_PWM(data, nr, p)((data)-&amp;gt;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 };
+static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
+0x138, 0x238, 0x338, 0x838, 0x938 };
+
+static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
+0x136, 0x236, 0x336, 0x836, 0x936 };
+static const u16 NCT6779_REG_CRITICAL_PWM[] = {
+0x137, 0x237, 0x337, 0x837, 0x937 };
+
+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"
+};
+
+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"
+};
+
+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 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 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 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 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
+= { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
+    0xa07 };
+
+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 };
+
+static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
+= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+#define NUM_TEMP10/* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP_FIXED6/* Max number of fixed temp attribute sets */
+
+static inline int reg_to_pwm_enable(int pwm, int mode)
+{
+if (mode == 0 &amp;amp;&amp;amp; pwm == 255)
+return 0;/* off*/
+return mode + 1;
+}
+
+static inline int pwm_enable_to_reg(int mode)
+{
+if (mode == 0)
+return 0;
+return mode - 1;
+}
+
+/*
+ * Conversions
+ */
+
+/* 1 is DC mode, output in ms */
+static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+return mode ? 400 * reg : 100 * reg;
+}
+
+static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+return SENSORS_LIMIT((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 &amp;lt;&amp;lt; divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+if ((reg &amp;amp; 0xff1f) == 0xff1f)
+return 0;
+
+reg = (reg &amp;amp; 0x1f) | ((reg &amp;amp; 0xff00) &amp;gt;&amp;gt; 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 &amp;lt;&amp;lt; divreg);
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+return 1 &amp;lt;&amp;lt; 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 SENSORS_LIMIT(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 */
+enum kinds kind;
+const char *name;
+
+struct device *hwmon_dev;
+struct mutex lock;
+
+u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+    * 3=temp_crit
+    */
+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;
+
+const s8 *ALARM_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_TIME[3];
+
+const u8 *REG_PWM_MODE;
+const u8 *PWM_MODE_MASK;
+
+const u16 *REG_PWM[7];/* [0]=pwm, [1]=start_output, [2]=stop_output,
+ * [3]=max_output, [4]=step_output,
+ * [5]=weight_duty_step, [6]=weight_duty_base
+ */
+const u16 *REG_PWM_READ;
+
+const u16 *REG_TEMP_MON;
+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[2];/* pwm temp, 0=base, 1=weight */
+
+const u16 *REG_WEIGHT_TEMP[3];/* 0=base, 1=hyst, 2=step */
+
+const u16 *REG_TEMP_OFFSET;
+
+const u16 *REG_ALARM;
+
+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[15][3];/* [0]=in, [1]=in_max, [2]=in_min */
+unsigned int rpm[5];
+u16 fan_min[5];
+u8 fan_div[5];
+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 temp_fixed_num;/* 3 or 6 */
+u8 temp_type[NUM_TEMP_FIXED];
+s8 temp_offset[NUM_TEMP_FIXED];
+s16 temp[3][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
+u64 alarms;
+
+u8 pwm_num;/* number of pwm */
+
+u8 pwm_mode[5]; /* 1-&amp;gt;DC variable voltage, 0-&amp;gt;PWM variable duty cycle */
+u8 pwm_enable[5]; /* 0-&amp;gt;off
+   * 1-&amp;gt;manual
+   * 2-&amp;gt;thermal cruise mode (also called SmartFan I)
+   * 3-&amp;gt;fan speed cruise mode
+   * 4-&amp;gt;SmartFan III
+   * 5-&amp;gt;enhanced variable thermal cruise (SmartFan IV)
+   */
+u8 pwm[7][5];/* [0]=pwm, [1]=start_output, [2]=stop_output,
+ * [3]=max_output, [4]=step_output,
+ * [5]=weight_duty_step, [6]=weight_duty_base
+ */
+u8 target_temp[5];
+s16 pwm_temp[5];
+u8 tolerance[5][2];
+
+u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+
+/* Automatic fan speed control registers */
+int auto_pwm_num;
+u8 auto_pwm[5][7];
+u8 auto_temp[5][7];
+
+u8 pwm_temp_sel[2][5];
+
+bool pwm_sel_enable[2][5];/* 0-&amp;gt;stop_val, 1-&amp;gt;weight;
+   * false-&amp;gt;off, true-&amp;gt;on
+   */
+u8 weight_temp[3][5];/* 0-&amp;gt;temp_step, 1-&amp;gt;temp_step_tol,
+ * 2-&amp;gt;temp_base
+ */
+
+u8 vid;
+u8 vrm;
+
+u16 have_temp;
+u16 have_temp_fixed;
+u16 have_in;
+};
+
+struct nct6775_sio_data {
+int sioreg;
+enum kinds kind;
+};
+
+static bool is_word_sized(struct nct6775_data *data, u16 reg)
+{
+switch (data-&amp;gt;kind) {
+case nct6775:
+return (((reg &amp;amp; 0xff00) == 0x100 ||
+    (reg &amp;amp; 0xff00) == 0x200) &amp;amp;&amp;amp;
+   ((reg &amp;amp; 0x00ff) == 0x50 ||
+    (reg &amp;amp; 0x00ff) == 0x53 ||
+    (reg &amp;amp; 0x00ff) == 0x55)) ||
+  (reg &amp;amp; 0xfff0) == 0x630 ||
+  reg == 0x640 || reg == 0x642 ||
+  reg == 0x662 ||
+  ((reg &amp;amp; 0xfff0) == 0x650 &amp;amp;&amp;amp; (reg &amp;amp; 0x000f) &amp;gt;= 0x06) ||
+  reg == 0x73 || reg == 0x75 || reg == 0x77;
+case nct6776:
+return (((reg &amp;amp; 0xff00) == 0x100 ||
+    (reg &amp;amp; 0xff00) == 0x200) &amp;amp;&amp;amp;
+   ((reg &amp;amp; 0x00ff) == 0x50 ||
+    (reg &amp;amp; 0x00ff) == 0x53 ||
+    (reg &amp;amp; 0x00ff) == 0x55)) ||
+  (reg &amp;amp; 0xfff0) == 0x630 ||
+  reg == 0x402 ||
+  reg == 0x640 || reg == 0x642 ||
+  ((reg &amp;amp; 0xfff0) == 0x650 &amp;amp;&amp;amp; (reg &amp;amp; 0x000f) &amp;gt;= 0x06) ||
+  reg == 0x73 || reg == 0x75 || reg == 0x77;
+case nct6779:
+return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
+  ((reg &amp;amp; 0xfff0) == 0x4b0 &amp;amp;&amp;amp; (reg &amp;amp; 0x000f) &amp;lt; 0x09) ||
+  reg == 0x402 ||
+  reg == 0x63a || reg == 0x63c || reg == 0x63e ||
+  reg == 0x640 || reg == 0x642 ||
+  reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
+  reg == 0x7b;
+}
+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 &amp;gt;&amp;gt; 8;
+if (data-&amp;gt;bank != bank) {
+outb_p(NCT6775_REG_BANK, data-&amp;gt;addr + ADDR_REG_OFFSET);
+outb_p(bank, data-&amp;gt;addr + DATA_REG_OFFSET);
+data-&amp;gt;bank = bank;
+}
+}
+
+static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
+{
+int res, word_sized = is_word_sized(data, reg);
+
+mutex_lock(&amp;amp;data-&amp;gt;lock);
+
+nct6775_set_bank(data, reg);
+outb_p(reg &amp;amp; 0xff, data-&amp;gt;addr + ADDR_REG_OFFSET);
+res = inb_p(data-&amp;gt;addr + DATA_REG_OFFSET);
+if (word_sized) {
+outb_p((reg &amp;amp; 0xff) + 1,
+       data-&amp;gt;addr + ADDR_REG_OFFSET);
+res = (res &amp;lt;&amp;lt; 8) + inb_p(data-&amp;gt;addr + DATA_REG_OFFSET);
+}
+
+mutex_unlock(&amp;amp;data-&amp;gt;lock);
+return res;
+}
+
+static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
+{
+int word_sized = is_word_sized(data, reg);
+
+mutex_lock(&amp;amp;data-&amp;gt;lock);
+
+nct6775_set_bank(data, reg);
+outb_p(reg &amp;amp; 0xff, data-&amp;gt;addr + ADDR_REG_OFFSET);
+if (word_sized) {
+outb_p(value &amp;gt;&amp;gt; 8, data-&amp;gt;addr + DATA_REG_OFFSET);
+outb_p((reg &amp;amp; 0xff) + 1,
+       data-&amp;gt;addr + ADDR_REG_OFFSET);
+}
+outb_p(value &amp;amp; 0xff, data-&amp;gt;addr + DATA_REG_OFFSET);
+
+mutex_unlock(&amp;amp;data-&amp;gt;lock);
+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 &amp;lt;&amp;lt;= 8;
+
+return res;
+}
+
+static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
+{
+if (!is_word_sized(data, reg))
+value &amp;gt;&amp;gt;= 8;
+return nct6775_write_value(data, reg, value);
+}
+
+/* This function assumes that the caller holds data-&amp;gt;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) &amp;amp; 0x70)
+    | (data-&amp;gt;fan_div[0] &amp;amp; 0x7);
+nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+break;
+case 1:
+reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) &amp;amp; 0x7)
+    | ((data-&amp;gt;fan_div[1] &amp;lt;&amp;lt; 4) &amp;amp; 0x70);
+nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+case 2:
+reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) &amp;amp; 0x70)
+    | (data-&amp;gt;fan_div[2] &amp;amp; 0x7);
+nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+break;
+case 3:
+reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) &amp;amp; 0x7)
+    | ((data-&amp;gt;fan_div[3] &amp;lt;&amp;lt; 4) &amp;amp; 0x70);
+nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+break;
+}
+}
+
+static void nct6775_write_fan_div_common(struct device *dev,
+ struct nct6775_data *data, int nr)
+{
+if (data-&amp;gt;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-&amp;gt;fan_div[0] = i &amp;amp; 0x7;
+data-&amp;gt;fan_div[1] = (i &amp;amp; 0x70) &amp;gt;&amp;gt; 4;
+i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+data-&amp;gt;fan_div[2] = i &amp;amp; 0x7;
+if (data-&amp;gt;has_fan &amp;amp; (1&amp;lt;&amp;lt;3))
+data-&amp;gt;fan_div[3] = (i &amp;amp; 0x70) &amp;gt;&amp;gt; 4;
+}
+
+static void nct6775_update_fan_div_common(struct device *dev,
+  struct nct6775_data *data)
+{
+if (data-&amp;gt;kind == nct6775)
+nct6775_update_fan_div(data);
+}
+
+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 &amp;lt; data-&amp;gt;pwm_num; i++) {
+if (!(data-&amp;gt;has_pwm &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+
+duty_is_dc = data-&amp;gt;REG_PWM_MODE[i] &amp;amp;&amp;amp;
+  (nct6775_read_value(data, data-&amp;gt;REG_PWM_MODE[i])
+   &amp;amp; data-&amp;gt;PWM_MODE_MASK[i]);
+data-&amp;gt;pwm_mode[i] = duty_is_dc;
+
+fanmodecfg = nct6775_read_value(data, data-&amp;gt;REG_FAN_MODE[i]);
+for (j = 0; j &amp;lt; ARRAY_SIZE(data-&amp;gt;REG_PWM); j++) {
+if (data-&amp;gt;REG_PWM[j] &amp;amp;&amp;amp; data-&amp;gt;REG_PWM[j][i]) {
+data-&amp;gt;pwm[j][i]
+  = nct6775_read_value(data,
+       data-&amp;gt;REG_PWM[j][i]);
+}
+}
+
+data-&amp;gt;pwm_enable[i] = reg_to_pwm_enable(data-&amp;gt;pwm[0][i],
+(fanmodecfg &amp;gt;&amp;gt; 4) &amp;amp; 7);
+
+data-&amp;gt;tolerance[i][0] = fanmodecfg &amp;amp; 0x0f;
+if (data-&amp;gt;kind == nct6779) {
+reg = nct6775_read_value(data,
+ NCT6779_REG_TOLERANCE_H[i]);
+data-&amp;gt;tolerance[i][0] |= (reg &amp;amp; 0x70) &amp;gt;&amp;gt; 1;
+}
+data-&amp;gt;tolerance[i][1] =
+nct6775_read_value(data,
+data-&amp;gt;REG_CRITICAL_TEMP_TOLERANCE[i]);
+
+data-&amp;gt;pwm_sel_enable[0][i] =
+nct6775_read_value(data, data-&amp;gt;REG_TEMP_SEL[0][i])
+&amp;amp; 0x80;
+data-&amp;gt;pwm_sel_enable[1][i] =
+nct6775_read_value(data, data-&amp;gt;REG_TEMP_SEL[1][i])
+&amp;amp; 0x80;
+
+/* Weight data */
+for (j = 0; j &amp;lt; 2; j++) {
+reg = nct6775_read_value(data,
+ data-&amp;gt;REG_TEMP_SEL[j][i]);
+data-&amp;gt;pwm_temp_sel[j][i] = reg &amp;amp; 0x1f;
+}
+/* Weight temp data */
+for (j = 0; j &amp;lt; 3; j++) {
+data-&amp;gt;weight_temp[j][i]
+  = nct6775_read_value(data,
+       data-&amp;gt;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;
+
+for (i = 0; i &amp;lt; data-&amp;gt;pwm_num; i++) {
+if (!(data-&amp;gt;has_pwm &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+
+for (j = 0; j &amp;lt; 3; j++) {
+data-&amp;gt;fan_time[j][i] =
+  nct6775_read_value(data, data-&amp;gt;REG_FAN_TIME[j][i]);
+}
+
+data-&amp;gt;target_temp[i] =
+nct6775_read_value(data, data-&amp;gt;REG_TARGET[i]) &amp;amp;
+(data-&amp;gt;pwm_mode[i] ? 0xff : 0x7f);
+data-&amp;gt;pwm_temp[i] =
+nct6775_read_value(data, data-&amp;gt;REG_TEMP_MON[i]);
+
+for (j = 0; j &amp;lt; data-&amp;gt;auto_pwm_num; j++) {
+data-&amp;gt;auto_pwm[i][j] =
+  nct6775_read_value(data,
+     NCT6775_AUTO_PWM(data, i, j));
+data-&amp;gt;auto_temp[i][j] =
+  nct6775_read_value(data,
+     NCT6775_AUTO_TEMP(data, i, j));
+}
+
+/* critical auto_pwm temperature data */
+data-&amp;gt;auto_temp[i][data-&amp;gt;auto_pwm_num] =
+nct6775_read_value(data, data-&amp;gt;REG_CRITICAL_TEMP[i]);
+
+switch (data-&amp;gt;kind) {
+case nct6775:
+reg = nct6775_read_value(data,
+ NCT6775_REG_CRITICAL_ENAB[i]);
+data-&amp;gt;auto_pwm[i][data-&amp;gt;auto_pwm_num] =
+(reg &amp;amp; 0x02) ? 0xff : 0x00;
+break;
+case nct6776:
+data-&amp;gt;auto_pwm[i][data-&amp;gt;auto_pwm_num] = 0xff;
+break;
+case nct6779:
+reg = nct6775_read_value(data,
+NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
+if (reg &amp;amp; 1)
+data-&amp;gt;auto_pwm[i][data-&amp;gt;auto_pwm_num] =
+  nct6775_read_value(data,
+NCT6779_REG_CRITICAL_PWM[i]);
+else
+data-&amp;gt;auto_pwm[i][data-&amp;gt;auto_pwm_num] = 0xff;
+break;
+}
+}
+}
+
+static struct nct6775_data *nct6775_update_device(struct device *dev)
+{
+struct nct6775_data *data = dev_get_drvdata(dev);
+int i, j;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+
+if (time_after(jiffies, data-&amp;gt;last_updated + HZ + HZ/2)
+ || !data-&amp;gt;valid) {
+/* Fan clock dividers */
+nct6775_update_fan_div_common(dev, data);
+
+/* Measured voltages and limits */
+for (i = 0; i &amp;lt; data-&amp;gt;in_num; i++) {
+if (!(data-&amp;gt;have_in &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+
+data-&amp;gt;in[i][0] = nct6775_read_value(data,
+    data-&amp;gt;REG_VIN[i]);
+data-&amp;gt;in[i][1] = nct6775_read_value(data,
+  data-&amp;gt;REG_IN_MINMAX[0][i]);
+data-&amp;gt;in[i][2] = nct6775_read_value(data,
+  data-&amp;gt;REG_IN_MINMAX[1][i]);
+}
+
+/* Measured fan speeds and limits */
+for (i = 0; i &amp;lt; 5; i++) {
+u16 reg;
+
+if (!(data-&amp;gt;has_fan &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+
+reg = nct6775_read_value(data, data-&amp;gt;REG_FAN[i]);
+data-&amp;gt;rpm[i] = data-&amp;gt;fan_from_reg(reg,
+  data-&amp;gt;fan_div[i]);
+
+if (data-&amp;gt;has_fan_min &amp;amp; (1 &amp;lt;&amp;lt; i))
+data-&amp;gt;fan_min[i] = nct6775_read_value(data,
+   data-&amp;gt;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-&amp;gt;has_fan_div &amp;amp;&amp;amp; (reg &amp;gt;= 0xff || reg == 0x00)
+    &amp;amp;&amp;amp; data-&amp;gt;fan_div[i] &amp;lt; 0x07) {
+dev_dbg(dev,
+"Increasing fan%d clock divider from %u to %u\n",
+i + 1, div_from_reg(data-&amp;gt;fan_div[i]),
+div_from_reg(data-&amp;gt;fan_div[i] + 1));
+data-&amp;gt;fan_div[i]++;
+nct6775_write_fan_div_common(dev, data, i);
+/* Preserve min limit if possible */
+if ((data-&amp;gt;has_fan_min &amp;amp; (1 &amp;lt;&amp;lt; i))
+ &amp;amp;&amp;amp; data-&amp;gt;fan_min[i] &amp;gt;= 2
+ &amp;amp;&amp;amp; data-&amp;gt;fan_min[i] != 255)
+nct6775_write_value(data,
+data-&amp;gt;REG_FAN_MIN[i],
+(data-&amp;gt;fan_min[i] /= 2));
+}
+}
+
+nct6775_update_pwm(dev);
+nct6775_update_pwm_limits(dev);
+
+/* Measured temperatures and limits */
+for (i = 0; i &amp;lt; NUM_TEMP; i++) {
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+for (j = 0; j &amp;lt; 4; j++) {
+if (data-&amp;gt;reg_temp[j][i])
+data-&amp;gt;temp[j][i]
+  = nct6775_read_temp(data,
+data-&amp;gt;reg_temp[j][i]);
+}
+if (!(data-&amp;gt;have_temp_fixed &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+data-&amp;gt;temp_offset[i]
+  = nct6775_read_value(data, data-&amp;gt;REG_TEMP_OFFSET[i]);
+}
+
+data-&amp;gt;alarms = 0;
+for (i = 0; i &amp;lt; 6; i++) {
+u8 alarm;
+if (!data-&amp;gt;REG_ALARM[i])
+continue;
+alarm = nct6775_read_value(data, data-&amp;gt;REG_ALARM[i]);
+data-&amp;gt;alarms |= ((u64)alarm) &amp;lt;&amp;lt; (i &amp;lt;&amp;lt; 3);
+}
+
+data-&amp;gt;last_updated = jiffies;
+data-&amp;gt;valid = 1;
+}
+
+mutex_unlock(&amp;amp;data-&amp;gt;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 nr = sattr-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+return sprintf(buf, "%ld\n", in_from_reg(data-&amp;gt;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 nr = sattr-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;in[nr][index] = in_to_reg(val, nr);
+nct6775_write_value(data, data-&amp;gt;REG_IN_MINMAX[index-1][nr],
+    data-&amp;gt;in[nr][index]);
+mutex_unlock(&amp;amp;data-&amp;gt;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-&amp;gt;ALARM_BITS[sattr-&amp;gt;index];
+return sprintf(buf, "%u\n",
+       (unsigned int)((data-&amp;gt;alarms &amp;gt;&amp;gt; nr) &amp;amp; 0x01));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
+static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
+static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
+static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
+static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
+static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
+static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
+static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
+
+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(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 7, 1);
+static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 8, 1);
+static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 9, 1);
+static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 10, 1);
+static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 11, 1);
+static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 12, 1);
+static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 13, 1);
+static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
+    store_in_reg, 14, 1);
+
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 1, 2);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 2, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 3, 2);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 4, 2);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 5, 2);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 6, 2);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 7, 2);
+static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 8, 2);
+static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 9, 2);
+static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 10, 2);
+static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 11, 2);
+static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 12, 2);
+static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 13, 2);
+static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
+  store_in_reg, 14, 2);
+
+static struct attribute *nct6775_attributes_in[15][5] = {
+{
+&amp;amp;sensor_dev_attr_in0_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in0_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in0_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in0_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in1_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in1_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in1_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in1_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in2_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in2_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in2_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in2_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in3_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in3_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in3_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in3_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in4_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in4_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in4_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in4_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in5_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in5_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in5_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in5_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in6_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in6_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in6_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in6_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in7_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in7_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in7_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in7_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in8_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in8_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in8_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in8_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in9_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in9_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in9_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in9_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in10_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in10_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in10_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in10_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in11_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in11_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in11_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in11_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in12_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in12_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in12_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in12_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in13_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in13_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in13_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in13_alarm.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_in14_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in14_min.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in14_max.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in14_alarm.dev_attr.attr,
+NULL
+},
+};
+
+static const struct attribute_group nct6775_group_in[15] = {
+{ .attrs = nct6775_attributes_in[0] },
+{ .attrs = nct6775_attributes_in[1] },
+{ .attrs = nct6775_attributes_in[2] },
+{ .attrs = nct6775_attributes_in[3] },
+{ .attrs = nct6775_attributes_in[4] },
+{ .attrs = nct6775_attributes_in[5] },
+{ .attrs = nct6775_attributes_in[6] },
+{ .attrs = nct6775_attributes_in[7] },
+{ .attrs = nct6775_attributes_in[8] },
+{ .attrs = nct6775_attributes_in[9] },
+{ .attrs = nct6775_attributes_in[10] },
+{ .attrs = nct6775_attributes_in[11] },
+{ .attrs = nct6775_attributes_in[12] },
+{ .attrs = nct6775_attributes_in[13] },
+{ .attrs = nct6775_attributes_in[14] },
+};
+
+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-&amp;gt;index;
+return sprintf(buf, "%d\n", data-&amp;gt;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-&amp;gt;index;
+return sprintf(buf, "%d\n",
+       data-&amp;gt;fan_from_reg_min(data-&amp;gt;fan_min[nr],
+      data-&amp;gt;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-&amp;gt;index;
+return sprintf(buf, "%u\n", div_from_reg(data-&amp;gt;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-&amp;gt;index;
+unsigned long val;
+int err;
+unsigned int reg;
+u8 new_div;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+if (!data-&amp;gt;has_fan_div) {
+/* NCT6776F or NCT6779D; we know this is a 13 bit register */
+if (!val) {
+val = 0xff1f;
+} else {
+if (val &amp;gt; 1350000U)
+val = 135000U;
+val = 1350000U / val;
+val = (val &amp;amp; 0x1f) | ((val &amp;lt;&amp;lt; 3) &amp;amp; 0xff00);
+}
+data-&amp;gt;fan_min[nr] = val;
+goto write_min;/* Leave fan divider alone */
+}
+if (!val) {
+/* No min limit, alarm disabled */
+data-&amp;gt;fan_min[nr] = 255;
+new_div = data-&amp;gt;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 &amp;gt;= 128 * 255) {
+/*
+ * Speed below this value cannot possibly be represented,
+ * even with the highest divider (128)
+ */
+data-&amp;gt;fan_min[nr] = 254;
+new_div = 7; /* 128 == (1 &amp;lt;&amp;lt; 7) */
+dev_warn(dev,
+ "fan%u low limit %lu below minimum %u, set to minimum\n",
+ nr + 1, val, data-&amp;gt;fan_from_reg_min(254, 7));
+} else if (!reg) {
+/*
+ * Speed above this value cannot possibly be represented,
+ * even with the lowest divider (1)
+ */
+data-&amp;gt;fan_min[nr] = 1;
+new_div = 0; /* 1 == (1 &amp;lt;&amp;lt; 0) */
+dev_warn(dev,
+ "fan%u low limit %lu above maximum %u, set to maximum\n",
+ nr + 1, val, data-&amp;gt;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 &amp;gt; 192 &amp;amp;&amp;amp; new_div &amp;lt; 7) {
+reg &amp;gt;&amp;gt;= 1;
+new_div++;
+}
+data-&amp;gt;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-&amp;gt;fan_div[nr]) {
+dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+nr + 1, div_from_reg(data-&amp;gt;fan_div[nr]),
+div_from_reg(new_div));
+data-&amp;gt;fan_div[nr] = new_div;
+nct6775_write_fan_div_common(dev, data, nr);
+/* Give the chip time to sample a new speed value */
+data-&amp;gt;last_updated = jiffies;
+}
+
+write_min:
+nct6775_write_value(data, data-&amp;gt;REG_FAN_MIN[nr], data-&amp;gt;fan_min[nr]);
+mutex_unlock(&amp;amp;data-&amp;gt;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, FAN_ALARM_BASE),
+SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
+SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
+SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
+SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 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_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 nct6775_data *data = nct6775_update_device(dev);
+struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+int nr = sattr-&amp;gt;index;
+return sprintf(buf, "%s\n", data-&amp;gt;temp_label[data-&amp;gt;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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+
+return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data-&amp;gt;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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+int err;
+long val;
+
+err = kstrtol(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;temp[index][nr] = LM75_TEMP_TO_REG(val);
+nct6775_write_temp(data, data-&amp;gt;reg_temp[index][nr],
+   data-&amp;gt;temp[index][nr]);
+mutex_unlock(&amp;amp;data-&amp;gt;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-&amp;gt;temp_offset[sattr-&amp;gt;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-&amp;gt;index;
+long val;
+int err;
+
+err = kstrtol(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;temp_offset[nr] = val;
+nct6775_write_value(data, data-&amp;gt;REG_TEMP_OFFSET[nr], val);
+mutex_unlock(&amp;amp;data-&amp;gt;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-&amp;gt;index;
+return sprintf(buf, "%d\n", (int)data-&amp;gt;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-&amp;gt;index;
+unsigned long val;
+int err;
+u8 vbat, diode, bit;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+if (val != 1 &amp;amp;&amp;amp; val != 3 &amp;amp;&amp;amp; val != 4)
+return -EINVAL;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+
+data-&amp;gt;temp_type[nr] = val;
+vbat = nct6775_read_value(data, data-&amp;gt;REG_VBAT) &amp;amp; ~(0x02 &amp;lt;&amp;lt; nr);
+diode = nct6775_read_value(data, data-&amp;gt;REG_DIODE) &amp;amp; ~(0x02 &amp;lt;&amp;lt; nr);
+bit = 0x02 &amp;lt;&amp;lt; nr;
+switch (val) {
+case 1:/* CPU diode (diode, current mode) */
+vbat |= bit;
+diode |= bit;
+break;
+case 3: /* diode, voltage mode */
+vbat |= bit;
+break;
+case 4:/* thermistor */
+break;
+};
+nct6775_write_value(data, data-&amp;gt;REG_VBAT, vbat);
+nct6775_write_value(data, data-&amp;gt;REG_DIODE, diode);
+
+mutex_unlock(&amp;amp;data-&amp;gt;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),
+SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
+SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
+SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
+SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
+SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
+SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
+SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
+SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
+};
+
+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),
+SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
+};
+
+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),
+SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      2, 1),
+SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      3, 1),
+SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      4, 1),
+SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      5, 1),
+SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      6, 1),
+SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      7, 1),
+SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      8, 1),
+SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      9, 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),
+SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      2, 2),
+SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      3, 2),
+SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      4, 2),
+SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      5, 2),
+SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      6, 2),
+SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      7, 2),
+SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      8, 2),
+SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      9, 2),
+};
+
+static struct sensor_device_attribute_2 sda_temp_crit[] = {
+SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      0, 3),
+SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      1, 3),
+SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      2, 3),
+SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      3, 3),
+SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      4, 3),
+SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      5, 3),
+SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      6, 3),
+SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      7, 3),
+SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      8, 3),
+SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+      9, 3),
+};
+
+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),
+SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+    store_temp_offset, 3),
+SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+    store_temp_offset, 4),
+SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+    store_temp_offset, 5),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
+SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 0),
+SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 1),
+SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 2),
+SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 3),
+SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 4),
+SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
+    store_temp_type, 5),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE),
+SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE + 1),
+SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE + 2),
+SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE + 3),
+SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE + 4),
+SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+    TEMP_ALARM_BASE + 5),
+};
+
+#define NUM_TEMP_ALARMARRAY_SIZE(sda_temp_alarm)
+
+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-&amp;gt;pwm_mode[sattr-&amp;gt;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-&amp;gt;index;
+unsigned long val;
+int err;
+u8 reg;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+if (val &amp;gt; 1)
+return -EINVAL;
+
+/* Setting DC mode is not supported for all chips/channels */
+if (data-&amp;gt;REG_PWM_MODE[nr] == 0) {
+if (val)
+return -EINVAL;
+return count;
+}
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;pwm_mode[nr] = val;
+reg = nct6775_read_value(data, data-&amp;gt;REG_PWM_MODE[nr]);
+reg &amp;amp;= ~data-&amp;gt;PWM_MODE_MASK[nr];
+if (val)
+reg |= data-&amp;gt;PWM_MODE_MASK[nr];
+nct6775_write_value(data, data-&amp;gt;REG_PWM_MODE[nr], reg);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+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-&amp;gt;pwm_enable[sattr-&amp;gt;index]);
+}
+
+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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+int pwm;
+
+/*
+ * For automatic fan control modes, show current pwm readings.
+ * Otherwise, show the configured value.
+ */
+if (index == 0 &amp;amp;&amp;amp; data-&amp;gt;pwm_enable[nr] &amp;gt; 1)
+pwm = nct6775_read_value(data, data-&amp;gt;REG_PWM_READ[nr]);
+else
+pwm = data-&amp;gt;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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int minval[7] = { 0, 1, 1, data-&amp;gt;pwm[2][nr], 0, 0, 0 };
+int maxval[7]
+  = { 255, 255, data-&amp;gt;pwm[3][nr] ? : 255, 255, 255, 255, 255 };
+int err;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+val = SENSORS_LIMIT(val, minval[index], maxval[index]);
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;pwm[index][nr] = val;
+nct6775_write_value(data, data-&amp;gt;REG_PWM[index][nr], val);
+mutex_unlock(&amp;amp;data-&amp;gt;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 &amp;lt; data-&amp;gt;auto_pwm_num - 1; i++) {
+if (data-&amp;gt;auto_temp[nr][i] &amp;gt; data-&amp;gt;auto_temp[nr][i + 1])
+return -EINVAL;
+}
+for (i = 0; i &amp;lt; data-&amp;gt;auto_pwm_num - 1; i++) {
+if (data-&amp;gt;auto_pwm[nr][i] &amp;gt; data-&amp;gt;auto_pwm[nr][i + 1])
+return -EINVAL;
+}
+/* validate critical temperature and pwm if enabled (pwm &amp;gt; 0) */
+if (data-&amp;gt;auto_pwm[nr][data-&amp;gt;auto_pwm_num]) {
+if (data-&amp;gt;auto_temp[nr][data-&amp;gt;auto_pwm_num - 1] &amp;gt;
+data-&amp;gt;auto_temp[nr][data-&amp;gt;auto_pwm_num] ||
+    data-&amp;gt;auto_pwm[nr][data-&amp;gt;auto_pwm_num - 1] &amp;gt;
+data-&amp;gt;auto_pwm[nr][data-&amp;gt;auto_pwm_num])
+return -EINVAL;
+}
+return 0;
+}
+
+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-&amp;gt;index;
+unsigned long val;
+int err;
+u16 reg;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+if (val &amp;gt; 5)
+return -EINVAL;
+
+if (val == 4 &amp;amp;&amp;amp; data-&amp;gt;kind != nct6775)
+return -EINVAL;
+
+if (val == 5 &amp;amp;&amp;amp; 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(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;pwm_enable[nr] = val;
+if (!val) {
+/*
+ * turn off pwm control: select manual mode, set pwm to maximum
+ */
+data-&amp;gt;pwm[0][nr] = 255;
+nct6775_write_value(data, data-&amp;gt;REG_PWM[0][nr], 255);
+}
+reg = nct6775_read_value(data, data-&amp;gt;REG_FAN_MODE[nr]);
+reg &amp;amp;= 0x0f;
+reg |= pwm_enable_to_reg(val) &amp;lt;&amp;lt; 4;
+nct6775_write_value(data, data-&amp;gt;REG_FAN_MODE[nr], reg);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+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_2 *sattr = to_sensor_dev_attr_2(attr);
+int i, src, sel = 0;
+
+src = data-&amp;gt;pwm_temp_sel[sattr-&amp;gt;index][sattr-&amp;gt;nr];
+
+for (i = 0; i &amp;lt; NUM_TEMP; i++) {
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+if (src == data-&amp;gt;temp_src[i]) {
+sel = i + 1;
+break;
+}
+}
+
+return sprintf(buf, "%d\n", sel);
+}
+
+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_2 *sattr = to_sensor_dev_attr_2(attr);
+int nr = sattr-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int err, reg, src;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+if (val == 0 || val &amp;gt; NUM_TEMP)
+return -EINVAL;
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; (val - 1))) || !data-&amp;gt;temp_src[val - 1])
+return -EINVAL;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+src = data-&amp;gt;temp_src[val - 1];
+data-&amp;gt;pwm_temp_sel[index][nr] = src;
+reg = nct6775_read_value(data, data-&amp;gt;REG_TEMP_SEL[index][nr]);
+reg &amp;amp;= 0xe0;
+reg |= src;
+nct6775_write_value(data, data-&amp;gt;REG_TEMP_SEL[index][nr], reg);
+mutex_unlock(&amp;amp;data-&amp;gt;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-&amp;gt;target_temp[sattr-&amp;gt;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-&amp;gt;index;
+long val;
+int err;
+
+err = kstrtol(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;target_temp[nr] = val;
+nct6775_write_value(data, data-&amp;gt;REG_TARGET[nr], val);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+static ssize_t
+show_auto_temp_hyst(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-&amp;gt;nr;
+int point = sattr-&amp;gt;index &amp;gt;= data-&amp;gt;auto_pwm_num ? 1 : 0;
+int tolerance = data-&amp;gt;tolerance[nr][point];
+int temp = data-&amp;gt;auto_temp[nr][sattr-&amp;gt;index];
+
+return sprintf(buf, "%d\n", (temp - tolerance) * 1000);
+}
+
+static ssize_t
+store_auto_temp_hyst(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-&amp;gt;nr;
+int point = sattr-&amp;gt;index &amp;gt;= data-&amp;gt;auto_pwm_num ? 1 : 0;
+u16 reg;
+long val;
+int err;
+int maxlimit[2][3] = { { 15, 7, 63 }, { 15, 7, 7 } };
+int mask[] = { 0x0f, 0x07, 0x07 };
+int temp;
+
+err = kstrtol(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+temp = data-&amp;gt;auto_temp[nr][sattr-&amp;gt;index];
+val = temp - DIV_ROUND_CLOSEST(val, 1000);
+
+/* Limit tolerance as needed */
+val = SENSORS_LIMIT(val, 0, maxlimit[point][data-&amp;gt;kind]);
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+if (point) {
+nct6775_write_value(data,
+    data-&amp;gt;REG_CRITICAL_TEMP_TOLERANCE[nr],
+    val);
+} else {
+reg = nct6775_read_value(data, data-&amp;gt;REG_FAN_MODE[nr]);
+reg = (reg &amp;amp; ~mask[nr]) | (val &amp;amp; mask[nr]);
+nct6775_write_value(data, data-&amp;gt;REG_FAN_MODE[nr], reg);
+if (data-&amp;gt;kind == nct6779) {
+reg = nct6775_read_value(data,
+ NCT6779_REG_TOLERANCE_H[nr]);
+reg = (reg &amp;amp; 0x70) | ((val &amp;amp; 0x38) &amp;lt;&amp;lt; 1);
+nct6775_write_value(data,
+    NCT6779_REG_TOLERANCE_H[nr], reg);
+}
+}
+
+data-&amp;gt;tolerance[nr][point] = val;
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
+
+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(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 SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+  store_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+  store_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+  store_pwm_enable, 4);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 4, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
+  store_target_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
+  store_target_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
+  store_target_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
+  store_target_temp, 3);
+static SENSOR_DEVICE_ATTR(pwm5_target, S_IWUSR | S_IRUGO, show_target_temp,
+  store_target_temp, 4);
+
+/* Smart Fan registers */
+
+static ssize_t
+show_pwm_sel_enable(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-&amp;gt;pwm_sel_enable[sattr-&amp;gt;index][sattr-&amp;gt;nr]);
+}
+
+static ssize_t
+store_pwm_sel_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_2 *sattr = to_sensor_dev_attr_2(attr);
+int nr = sattr-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int err;
+u8 reg;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+if (val &amp;gt; 1)
+return -EINVAL;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;pwm_sel_enable[index][nr] = val;
+reg = nct6775_read_value(data, data-&amp;gt;REG_TEMP_SEL[index][nr]);
+reg &amp;amp;= 0x7f;
+if (val)
+reg |= 0x80;
+nct6775_write_value(data, data-&amp;gt;REG_TEMP_SEL[index][nr], reg);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+
+return sprintf(buf, "%d\n", data-&amp;gt;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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int err;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;weight_temp[index][nr] = val;
+nct6775_write_value(data, data-&amp;gt;REG_WEIGHT_TEMP[index][nr], val);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(pwm1_stop_output_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_stop_output_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_stop_output_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_stop_output_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_stop_output_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_enable, S_IWUSR | S_IRUGO,
+    show_pwm_sel_enable, store_pwm_sel_enable, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
+    show_pwm_temp_sel, store_pwm_temp_sel, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
+    show_weight_temp, store_weight_temp, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
+    show_pwm, store_pwm, 0, 5);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
+    show_pwm, store_pwm, 1, 5);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
+    show_pwm, store_pwm, 2, 5);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
+    show_pwm, store_pwm, 3, 5);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
+    show_pwm, store_pwm, 4, 5);
+
+/* duty_base is not supported on all chips */
+static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
+SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
+      show_pwm, store_pwm, 0, 6),
+SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
+      show_pwm, store_pwm, 1, 6),
+SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
+      show_pwm, store_pwm, 2, 6),
+SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
+      show_pwm, store_pwm, 3, 6),
+SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
+      show_pwm, store_pwm, 4, 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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+
+return sprintf(buf, "%d\n",
+       step_time_from_reg(data-&amp;gt;fan_time[index][nr],
+  data-&amp;gt;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-&amp;gt;nr;
+int index = sattr-&amp;gt;index;
+unsigned long val;
+int err;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+
+val = step_time_to_reg(val, data-&amp;gt;pwm_mode[nr]);
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;fan_time[index][nr] = val;
+nct6775_write_value(data, data-&amp;gt;REG_FAN_TIME[index][nr], val);
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+struct nct6775_data *data = dev_get_drvdata(dev);
+
+return sprintf(buf, "%s\n", data-&amp;gt;name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+    store_fan_time, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
+    show_fan_time, store_fan_time, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
+    show_fan_time, store_fan_time, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
+    show_fan_time, store_fan_time, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
+    show_fan_time, store_fan_time, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
+    show_fan_time, store_fan_time, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_start_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_start_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_start_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_start_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_start_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_stop_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_stop_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_stop_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_stop_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_stop_output, S_IWUSR | S_IRUGO, show_pwm,
+    store_pwm, 4, 2);
+
+/* max_output is not supported on all chips */
+static struct sensor_device_attribute_2 sda_max_output[] = {
+SENSOR_ATTR_2(pwm1_max_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      0, 3),
+SENSOR_ATTR_2(pwm2_max_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      1, 3),
+SENSOR_ATTR_2(pwm3_max_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      2, 3),
+SENSOR_ATTR_2(pwm4_max_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      3, 3),
+SENSOR_ATTR_2(pwm5_max_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      4, 3),
+};
+
+/* step_output is not supported on all chips */
+static struct sensor_device_attribute_2 sda_step_output[] = {
+SENSOR_ATTR_2(pwm1_step_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      0, 4),
+SENSOR_ATTR_2(pwm2_step_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      1, 4),
+SENSOR_ATTR_2(pwm3_step_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      2, 4),
+SENSOR_ATTR_2(pwm4_step_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      3, 4),
+SENSOR_ATTR_2(pwm5_step_output, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+      4, 4),
+};
+
+static struct attribute *nct6775_attributes_pwm[5][19] = {
+{
+&amp;amp;sensor_dev_attr_pwm1.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_mode.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_stop_output_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_target.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_start_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_stop_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_pwm2.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_mode.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_stop_output_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_target.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_start_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_stop_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_pwm3.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_mode.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_stop_output_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_target.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_start_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_stop_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_pwm4.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_mode.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_stop_output_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_target.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_start_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_stop_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
+NULL
+},
+{
+&amp;amp;sensor_dev_attr_pwm5.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_mode.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_stop_output_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_enable.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_target.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_start_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_stop_output.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
+&amp;amp;sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
+NULL
+},
+};
+
+static const struct attribute_group nct6775_group_pwm[5] = {
+{ .attrs = nct6775_attributes_pwm[0] },
+{ .attrs = nct6775_attributes_pwm[1] },
+{ .attrs = nct6775_attributes_pwm[2] },
+{ .attrs = nct6775_attributes_pwm[3] },
+{ .attrs = nct6775_attributes_pwm[4] },
+};
+
+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-&amp;gt;auto_pwm[sattr-&amp;gt;nr][sattr-&amp;gt;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-&amp;gt;nr;
+int point = sattr-&amp;gt;index;
+unsigned long val;
+int err;
+u8 reg;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err &amp;lt; 0)
+return err;
+if (val &amp;gt; 255)
+return -EINVAL;
+
+if (point == data-&amp;gt;auto_pwm_num) {
+if (data-&amp;gt;kind != nct6775 &amp;amp;&amp;amp; !val)
+return -EINVAL;
+if (data-&amp;gt;kind != nct6779 &amp;amp;&amp;amp; val)
+val = 0xff;
+}
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;auto_pwm[nr][point] = val;
+if (point &amp;lt; data-&amp;gt;auto_pwm_num) {
+nct6775_write_value(data,
+    NCT6775_AUTO_PWM(data, nr, point),
+    data-&amp;gt;auto_pwm[nr][point]);
+} else {
+switch (data-&amp;gt;kind) {
+case nct6775:
+/* disable if needed (pwm == 0) */
+reg = nct6775_read_value(data,
+ NCT6775_REG_CRITICAL_ENAB[nr]);
+if (val)
+reg |= 0x02;
+else
+reg &amp;amp;= ~0x02;
+nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
+    reg);
+break;
+case nct6776:
+break; /* always enabled, nothing to do */
+case nct6779:
+nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+    val);
+reg = nct6775_read_value(data,
+NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+if (val == 255)
+reg &amp;amp;= ~0x01;
+else
+reg |= 0x01;
+nct6775_write_value(data,
+    NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+    reg);
+break;
+}
+}
+mutex_unlock(&amp;amp;data-&amp;gt;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-&amp;gt;nr;
+int point = sattr-&amp;gt;index;
+
+/*
+ * We don't know for sure if the temperature is signed or unsigned.
+ * Assume it is unsigned.
+ */
+return sprintf(buf, "%d\n", data-&amp;gt;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-&amp;gt;nr;
+int point = sattr-&amp;gt;index;
+unsigned long val;
+int err;
+
+err = kstrtoul(buf, 10, &amp;amp;val);
+if (err)
+return err;
+if (val &amp;gt; 255000)
+return -EINVAL;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
+if (point &amp;lt; data-&amp;gt;auto_pwm_num) {
+nct6775_write_value(data,
+    NCT6775_AUTO_TEMP(data, nr, point),
+    data-&amp;gt;auto_temp[nr][point]);
+} else {
+nct6775_write_value(data, data-&amp;gt;REG_CRITICAL_TEMP[nr],
+    data-&amp;gt;auto_temp[nr][point]);
+}
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return count;
+}
+
+/*
+ * The number of auto-point trip points is chip dependent.
+ * Need to check support while generating/removing attribute files.
+ */
+static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
+SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 0),
+SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 0),
+SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 0),
+SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 1),
+SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 1),
+SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 1),
+SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 2),
+SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 2),
+SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 2),
+SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 3),
+SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 3),
+SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 3),
+SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 4),
+SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 4),
+SENSOR_ATTR_2(pwm1_auto_point5_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 4),
+SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 5),
+SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 5),
+SENSOR_ATTR_2(pwm1_auto_point6_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 5),
+SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 0, 6),
+SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 0, 6),
+SENSOR_ATTR_2(pwm1_auto_point7_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 0, 6),
+
+SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 0),
+SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 0),
+SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 0),
+SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 1),
+SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 1),
+SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 1),
+SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 2),
+SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 2),
+SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 2),
+SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 3),
+SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 3),
+SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 3),
+SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 4),
+SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 4),
+SENSOR_ATTR_2(pwm2_auto_point5_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 4),
+SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 5),
+SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 5),
+SENSOR_ATTR_2(pwm2_auto_point6_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 5),
+SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 1, 6),
+SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 1, 6),
+SENSOR_ATTR_2(pwm2_auto_point7_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 1, 6),
+
+SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 0),
+SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 0),
+SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 0),
+SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 1),
+SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 1),
+SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 1),
+SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 2),
+SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 2),
+SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 2),
+SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 3),
+SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 3),
+SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 3),
+SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 4),
+SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 4),
+SENSOR_ATTR_2(pwm3_auto_point5_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 4),
+SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 5),
+SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 5),
+SENSOR_ATTR_2(pwm3_auto_point6_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 5),
+SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 2, 6),
+SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 2, 6),
+SENSOR_ATTR_2(pwm3_auto_point7_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 2, 6),
+
+SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 0),
+SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 0),
+SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 0),
+SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 1),
+SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 1),
+SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 1),
+SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 2),
+SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 2),
+SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 2),
+SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 3),
+SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 3),
+SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 3),
+SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 4),
+SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 4),
+SENSOR_ATTR_2(pwm4_auto_point5_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 4),
+SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 5),
+SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 5),
+SENSOR_ATTR_2(pwm4_auto_point6_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 5),
+SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 3, 6),
+SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 3, 6),
+SENSOR_ATTR_2(pwm4_auto_point7_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 3, 6),
+
+SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 0),
+SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 0),
+SENSOR_ATTR_2(pwm5_auto_point1_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 0),
+SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 1),
+SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 1),
+SENSOR_ATTR_2(pwm5_auto_point2_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 1),
+SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 2),
+SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 2),
+SENSOR_ATTR_2(pwm5_auto_point3_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 2),
+SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 3),
+SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 3),
+SENSOR_ATTR_2(pwm5_auto_point4_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 3),
+SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 4),
+SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 4),
+SENSOR_ATTR_2(pwm5_auto_point5_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 4),
+SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 5),
+SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 5),
+SENSOR_ATTR_2(pwm5_auto_point6_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 5),
+SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
+  show_auto_pwm, store_auto_pwm, 4, 6),
+SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
+  show_auto_temp, store_auto_temp, 4, 6),
+SENSOR_ATTR_2(pwm5_auto_point7_temp_hyst, S_IWUSR | S_IRUGO,
+  show_auto_temp_hyst, store_auto_temp_hyst, 4, 6),
+};
+
+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-&amp;gt;vid, data-&amp;gt;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);
+struct nct6775_sio_data *sio_data = dev-&amp;gt;platform_data;
+int nr = to_sensor_dev_attr(attr)-&amp;gt;index - INTRUSION_ALARM_BASE;
+unsigned long val;
+u8 reg;
+
+if (kstrtoul(buf, 10, &amp;amp;val) || val != 0)
+return -EINVAL;
+
+mutex_lock(&amp;amp;data-&amp;gt;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.
+ */
+superio_enter(sio_data-&amp;gt;sioreg);
+superio_select(sio_data-&amp;gt;sioreg, NCT6775_LD_ACPI);
+reg = superio_inb(sio_data-&amp;gt;sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+superio_outb(sio_data-&amp;gt;sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+reg &amp;amp;= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+superio_outb(sio_data-&amp;gt;sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+superio_exit(sio_data-&amp;gt;sioreg);
+
+data-&amp;gt;valid = 0;/* Force cache refresh */
+
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+
+return count;
+}
+
+static struct sensor_device_attribute sda_caseopen[] = {
+SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+    clear_caseopen, INTRUSION_ALARM_BASE),
+SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+    clear_caseopen, INTRUSION_ALARM_BASE + 1),
+};
+
+/*
+ * Driver and device management
+ */
+
+static void nct6775_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 nct6775_data *data = dev_get_drvdata(dev);
+
+for (i = 0; i &amp;lt; data-&amp;gt;pwm_num; i++)
+sysfs_remove_group(&amp;amp;dev-&amp;gt;kobj, &amp;amp;nct6775_group_pwm[i]);
+
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_max_output); i++)
+device_remove_file(dev, &amp;amp;sda_max_output[i].dev_attr);
+
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_step_output); i++)
+device_remove_file(dev, &amp;amp;sda_max_output[i].dev_attr);
+
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_weight_duty_base); i++)
+device_remove_file(dev, &amp;amp;sda_weight_duty_base[i].dev_attr);
+
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_auto_pwm_arrays); i++)
+device_remove_file(dev, &amp;amp;sda_auto_pwm_arrays[i].dev_attr);
+
+for (i = 0; i &amp;lt; data-&amp;gt;in_num; i++)
+sysfs_remove_group(&amp;amp;dev-&amp;gt;kobj, &amp;amp;nct6775_group_in[i]);
+
+for (i = 0; i &amp;lt; 5; i++) {
+device_remove_file(dev, &amp;amp;sda_fan_input[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_fan_alarm[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_fan_div[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_fan_min[i].dev_attr);
+}
+for (i = 0; i &amp;lt; NUM_TEMP; i++) {
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+device_remove_file(dev, &amp;amp;sda_temp_input[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_temp_label[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_temp_max[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_temp_max_hyst[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_temp_crit[i].dev_attr);
+if (!(data-&amp;gt;have_temp_fixed &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+device_remove_file(dev, &amp;amp;sda_temp_type[i].dev_attr);
+device_remove_file(dev, &amp;amp;sda_temp_offset[i].dev_attr);
+if (i &amp;gt;= NUM_TEMP_ALARM)
+continue;
+device_remove_file(dev, &amp;amp;sda_temp_alarm[i].dev_attr);
+}
+
+device_remove_file(dev, &amp;amp;sda_caseopen[0].dev_attr);
+device_remove_file(dev, &amp;amp;sda_caseopen[1].dev_attr);
+
+device_remove_file(dev, &amp;amp;dev_attr_name);
+device_remove_file(dev, &amp;amp;dev_attr_cpu0_vid);
+}
+
+/* Get the monitoring functions started */
+static inline void __devinit nct6775_init_device(struct nct6775_data *data)
+{
+int i;
+u8 tmp, diode;
+
+/* Start monitoring if needed */
+if (data-&amp;gt;REG_CONFIG) {
+tmp = nct6775_read_value(data, data-&amp;gt;REG_CONFIG);
+if (!(tmp &amp;amp; 0x01))
+nct6775_write_value(data, data-&amp;gt;REG_CONFIG, tmp | 0x01);
+}
+
+/* Enable temperature sensors if needed */
+for (i = 0; i &amp;lt; NUM_TEMP; i++) {
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+if (!data-&amp;gt;reg_temp_config[i])
+continue;
+tmp = nct6775_read_value(data, data-&amp;gt;reg_temp_config[i]);
+if (tmp &amp;amp; 0x01)
+nct6775_write_value(data, data-&amp;gt;reg_temp_config[i],
+    tmp &amp;amp; 0xfe);
+}
+
+/* Enable VBAT monitoring if needed */
+tmp = nct6775_read_value(data, data-&amp;gt;REG_VBAT);
+if (!(tmp &amp;amp; 0x01))
+nct6775_write_value(data, data-&amp;gt;REG_VBAT, tmp | 0x01);
+
+diode = nct6775_read_value(data, data-&amp;gt;REG_DIODE);
+
+for (i = 0; i &amp;lt; data-&amp;gt;temp_fixed_num; i++) {
+if (!(data-&amp;gt;have_temp_fixed &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+if ((tmp &amp;amp; (0x02 &amp;lt;&amp;lt; i)))/* diode */
+data-&amp;gt;temp_type[i] = 3 - ((diode &amp;gt;&amp;gt; i) &amp;amp; 0x02);
+else/* thermistor */
+data-&amp;gt;temp_type[i] = 4;
+}
+}
+
+static void __devinit
+nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
+ struct nct6775_data *data)
+{
+int regval;
+bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
+bool pwm3pin, pwm4pin, pwm5pin;
+
+superio_enter(sio_data-&amp;gt;sioreg);
+
+/* fan4 and fan5 share some pins with the GPIO and serial flash */
+if (data-&amp;gt;kind == nct6775) {
+regval = superio_inb(sio_data-&amp;gt;sioreg, 0x2c);
+
+fan3pin = regval &amp;amp; (1 &amp;lt;&amp;lt; 6);
+fan3min = fan3pin;
+pwm3pin = regval &amp;amp; (1 &amp;lt;&amp;lt; 7);
+
+/* On NCT6775, fan4 shares pins with the fdc interface */
+fan4pin = !(superio_inb(sio_data-&amp;gt;sioreg, 0x2A) &amp;amp; 0x80);
+fan4min = 0;
+fan5pin = 0;
+pwm4pin = 0;
+pwm5pin = 0;
+} else if (data-&amp;gt;kind == nct6776) {
+bool gpok = superio_inb(sio_data-&amp;gt;sioreg, 0x27) &amp;amp; 0x80;
+
+superio_select(sio_data-&amp;gt;sioreg, NCT6775_LD_HWM);
+regval = superio_inb(sio_data-&amp;gt;sioreg, SIO_REG_ENABLE);
+
+if (regval &amp;amp; 0x80)
+fan3pin = gpok;
+else
+fan3pin = !(superio_inb(sio_data-&amp;gt;sioreg, 0x24) &amp;amp; 0x40);
+
+if (regval &amp;amp; 0x40)
+fan4pin = gpok;
+else
+fan4pin = superio_inb(sio_data-&amp;gt;sioreg, 0x1C) &amp;amp; 0x01;
+
+if (regval &amp;amp; 0x20)
+fan5pin = gpok;
+else
+fan5pin = superio_inb(sio_data-&amp;gt;sioreg, 0x1C) &amp;amp; 0x02;
+
+fan4min = fan4pin;
+fan3min = fan3pin;
+pwm3pin = fan3pin;
+pwm4pin = 0;
+pwm5pin = 0;
+} else {/* NCT6779D */
+regval = superio_inb(sio_data-&amp;gt;sioreg, 0x1c);
+
+fan3pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 5));
+fan4pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 6));
+fan5pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 7));
+
+pwm3pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 0));
+pwm4pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 1));
+pwm5pin = !(regval &amp;amp; (1 &amp;lt;&amp;lt; 2));
+
+fan3min = fan3pin;
+fan4min = fan4pin;
+}
+
+superio_exit(sio_data-&amp;gt;sioreg);
+
+data-&amp;gt;has_fan = data-&amp;gt;has_fan_min = 0x03; /* fan1 and fan2 */
+data-&amp;gt;has_fan |= fan3pin &amp;lt;&amp;lt; 2;
+data-&amp;gt;has_fan_min |= fan3min &amp;lt;&amp;lt; 2;
+
+data-&amp;gt;has_fan |= (fan4pin &amp;lt;&amp;lt; 3) | (fan5pin &amp;lt;&amp;lt; 4);
+data-&amp;gt;has_fan_min |= (fan4min &amp;lt;&amp;lt; 3) | (fan5pin &amp;lt;&amp;lt; 4);
+
+data-&amp;gt;has_pwm = 0x03 | (pwm3pin &amp;lt;&amp;lt; 2) | (pwm4pin &amp;lt;&amp;lt; 3) | (pwm5pin &amp;lt;&amp;lt; 4);
+}
+
+static int __devinit nct6775_probe(struct platform_device *pdev)
+{
+struct device *dev = &amp;amp;pdev-&amp;gt;dev;
+struct nct6775_sio_data *sio_data = dev-&amp;gt;platform_data;
+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_alternate, *reg_temp_crit;
+int num_reg_temp;
+
+res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+if (!devm_request_region(&amp;amp;pdev-&amp;gt;dev, res-&amp;gt;start, IOREGION_LENGTH,
+ DRVNAME))
+return -EBUSY;
+
+data = devm_kzalloc(&amp;amp;pdev-&amp;gt;dev, sizeof(struct nct6775_data),
+    GFP_KERNEL);
+if (!data)
+return -ENOMEM;
+
+data-&amp;gt;kind = sio_data-&amp;gt;kind;
+data-&amp;gt;addr = res-&amp;gt;start;
+mutex_init(&amp;amp;data-&amp;gt;lock);
+mutex_init(&amp;amp;data-&amp;gt;update_lock);
+data-&amp;gt;name = nct6775_device_names[data-&amp;gt;kind];
+platform_set_drvdata(pdev, data);
+
+switch (data-&amp;gt;kind) {
+case nct6775:
+data-&amp;gt;in_num = 9;
+data-&amp;gt;pwm_num = 3;
+data-&amp;gt;auto_pwm_num = 6;
+data-&amp;gt;has_fan_div = true;
+data-&amp;gt;temp_fixed_num = 3;
+
+data-&amp;gt;ALARM_BITS = NCT6775_ALARM_BITS;
+
+data-&amp;gt;fan_from_reg = fan_from_reg16;
+data-&amp;gt;fan_from_reg_min = fan_from_reg8;
+
+data-&amp;gt;temp_label = nct6775_temp_label;
+data-&amp;gt;temp_label_num = ARRAY_SIZE(nct6775_temp_label);
+
+data-&amp;gt;REG_CONFIG = NCT6775_REG_CONFIG;
+data-&amp;gt;REG_VBAT = NCT6775_REG_VBAT;
+data-&amp;gt;REG_DIODE = NCT6775_REG_DIODE;
+data-&amp;gt;REG_VIN = NCT6775_REG_IN;
+data-&amp;gt;REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+data-&amp;gt;REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+data-&amp;gt;REG_TARGET = NCT6775_REG_TARGET;
+data-&amp;gt;REG_FAN = NCT6775_REG_FAN;
+data-&amp;gt;REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+data-&amp;gt;REG_FAN_MIN = NCT6775_REG_FAN_MIN;
+data-&amp;gt;REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+data-&amp;gt;REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+data-&amp;gt;REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+data-&amp;gt;REG_PWM[0] = NCT6775_REG_PWM;
+data-&amp;gt;REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+data-&amp;gt;REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+data-&amp;gt;REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
+data-&amp;gt;REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
+data-&amp;gt;REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+data-&amp;gt;REG_PWM_READ = NCT6775_REG_PWM_READ;
+data-&amp;gt;REG_PWM_MODE = NCT6775_REG_PWM_MODE;
+data-&amp;gt;PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
+data-&amp;gt;REG_TEMP_MON = NCT6775_REG_TEMP_MON;
+data-&amp;gt;REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+data-&amp;gt;REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+data-&amp;gt;REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+data-&amp;gt;REG_CRITICAL_TEMP_TOLERANCE
+  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+data-&amp;gt;REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+data-&amp;gt;REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+data-&amp;gt;REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
+data-&amp;gt;REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+data-&amp;gt;REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+data-&amp;gt;REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+data-&amp;gt;REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+data-&amp;gt;REG_ALARM = NCT6775_REG_ALARM;
+
+reg_temp = NCT6775_REG_TEMP;
+num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+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-&amp;gt;in_num = 9;
+data-&amp;gt;pwm_num = 3;
+data-&amp;gt;auto_pwm_num = 4;
+data-&amp;gt;has_fan_div = false;
+data-&amp;gt;temp_fixed_num = 3;
+
+data-&amp;gt;ALARM_BITS = NCT6776_ALARM_BITS;
+
+data-&amp;gt;fan_from_reg = fan_from_reg13;
+data-&amp;gt;fan_from_reg_min = fan_from_reg13;
+
+data-&amp;gt;temp_label = nct6776_temp_label;
+data-&amp;gt;temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+data-&amp;gt;REG_CONFIG = NCT6775_REG_CONFIG;
+data-&amp;gt;REG_VBAT = NCT6775_REG_VBAT;
+data-&amp;gt;REG_DIODE = NCT6775_REG_DIODE;
+data-&amp;gt;REG_VIN = NCT6775_REG_IN;
+data-&amp;gt;REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+data-&amp;gt;REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+data-&amp;gt;REG_TARGET = NCT6775_REG_TARGET;
+data-&amp;gt;REG_FAN = NCT6775_REG_FAN;
+data-&amp;gt;REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+data-&amp;gt;REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+data-&amp;gt;REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+data-&amp;gt;REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+data-&amp;gt;REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+data-&amp;gt;REG_PWM[0] = NCT6775_REG_PWM;
+data-&amp;gt;REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+data-&amp;gt;REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+data-&amp;gt;REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+data-&amp;gt;REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+data-&amp;gt;REG_PWM_READ = NCT6775_REG_PWM_READ;
+data-&amp;gt;REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+data-&amp;gt;PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+data-&amp;gt;REG_TEMP_MON = NCT6775_REG_TEMP_MON;
+data-&amp;gt;REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+data-&amp;gt;REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+data-&amp;gt;REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+data-&amp;gt;REG_CRITICAL_TEMP_TOLERANCE
+  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+data-&amp;gt;REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+data-&amp;gt;REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+data-&amp;gt;REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
+data-&amp;gt;REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+data-&amp;gt;REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+data-&amp;gt;REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+data-&amp;gt;REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+data-&amp;gt;REG_ALARM = NCT6775_REG_ALARM;
+
+reg_temp = NCT6775_REG_TEMP;
+num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+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-&amp;gt;in_num = 15;
+data-&amp;gt;pwm_num = 5;
+data-&amp;gt;auto_pwm_num = 4;
+data-&amp;gt;has_fan_div = false;
+data-&amp;gt;temp_fixed_num = 6;
+
+data-&amp;gt;ALARM_BITS = NCT6779_ALARM_BITS;
+
+data-&amp;gt;fan_from_reg = fan_from_reg13;
+data-&amp;gt;fan_from_reg_min = fan_from_reg13;
+
+data-&amp;gt;temp_label = nct6779_temp_label;
+data-&amp;gt;temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+data-&amp;gt;REG_CONFIG = NCT6775_REG_CONFIG;
+data-&amp;gt;REG_VBAT = NCT6775_REG_VBAT;
+data-&amp;gt;REG_DIODE = NCT6775_REG_DIODE;
+data-&amp;gt;REG_VIN = NCT6779_REG_IN;
+data-&amp;gt;REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+data-&amp;gt;REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+data-&amp;gt;REG_TARGET = NCT6775_REG_TARGET;
+data-&amp;gt;REG_FAN = NCT6779_REG_FAN;
+data-&amp;gt;REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+data-&amp;gt;REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+data-&amp;gt;REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+data-&amp;gt;REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+data-&amp;gt;REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+data-&amp;gt;REG_PWM[0] = NCT6775_REG_PWM;
+data-&amp;gt;REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+data-&amp;gt;REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+data-&amp;gt;REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+data-&amp;gt;REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+data-&amp;gt;REG_PWM_READ = NCT6775_REG_PWM_READ;
+data-&amp;gt;REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+data-&amp;gt;PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+data-&amp;gt;REG_TEMP_MON = NCT6775_REG_TEMP_MON;
+data-&amp;gt;REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+data-&amp;gt;REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+data-&amp;gt;REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+data-&amp;gt;REG_CRITICAL_TEMP_TOLERANCE
+  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+data-&amp;gt;REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+data-&amp;gt;REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+data-&amp;gt;REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
+data-&amp;gt;REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+data-&amp;gt;REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+data-&amp;gt;REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+data-&amp;gt;REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+data-&amp;gt;REG_ALARM = NCT6779_REG_ALARM;
+
+reg_temp = NCT6779_REG_TEMP;
+num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+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-&amp;gt;have_in = (1 &amp;lt;&amp;lt; data-&amp;gt;in_num) - 1;
+data-&amp;gt;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 &amp;lt; num_reg_temp; i++) {
+if (reg_temp[i] == 0)
+continue;
+
+src = nct6775_read_value(data, data-&amp;gt;REG_TEMP_SOURCE[i]) &amp;amp; 0x1f;
+if (!src || (mask &amp;amp; (1 &amp;lt;&amp;lt; src)))
+available |= 1 &amp;lt;&amp;lt; i;
+
+mask |= 1 &amp;lt;&amp;lt; src;
+}
+
+/*
+ * Now find unmonitored temperature registers and enable monitoring
+ * if additional monitoring registers are available.
+ */
+for (i = 0; i &amp;lt; ARRAY_SIZE(data-&amp;gt;REG_TEMP_SEL) &amp;amp;&amp;amp; available; i++) {
+int j;
+
+if (!data-&amp;gt;REG_TEMP_SEL[i])
+continue;
+for (j = 0; j &amp;lt; data-&amp;gt;pwm_num &amp;amp;&amp;amp; available; j++) {
+int index;
+
+if (!data-&amp;gt;REG_TEMP_SEL[i][j])
+continue;
+src = nct6775_read_value(data,
+ data-&amp;gt;REG_TEMP_SEL[i][j]);
+src &amp;amp;= 0x1f;
+if (!src || (mask &amp;amp; (1 &amp;lt;&amp;lt; src)))
+continue;
+if (src &amp;gt;= data-&amp;gt;temp_label_num ||
+    !strlen(data-&amp;gt;temp_label[src])) {
+dev_info(dev,
+ "Select source %d:%d reg 0x%x invalid (%d)\n",
+ i, j, data-&amp;gt;REG_TEMP_SEL[i][j], src);
+continue;
+}
+
+index = __ffs(available);
+nct6775_write_value(data,
+    data-&amp;gt;REG_TEMP_SOURCE[index],
+    src);
+available &amp;amp;= ~(1 &amp;lt;&amp;lt; index);
+mask |= 1 &amp;lt;&amp;lt; src;
+}
+}
+
+mask = 0;
+s = NUM_TEMP_FIXED;/* First dynamic temperature attribute */
+for (i = 0; i &amp;lt; num_reg_temp; i++) {
+if (reg_temp[i] == 0)
+continue;
+
+src = nct6775_read_value(data, data-&amp;gt;REG_TEMP_SOURCE[i]) &amp;amp; 0x1f;
+if (!src || (mask &amp;amp; (1 &amp;lt;&amp;lt; src)))
+continue;
+
+if (src &amp;gt;= data-&amp;gt;temp_label_num ||
+    !strlen(data-&amp;gt;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-&amp;gt;REG_TEMP_SOURCE[i], reg_temp[i]);
+continue;
+}
+
+mask |= 1 &amp;lt;&amp;lt; src;
+
+/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+if (src &amp;lt;= data-&amp;gt;temp_fixed_num) {
+data-&amp;gt;have_temp |= 1 &amp;lt;&amp;lt; (src - 1);
+data-&amp;gt;have_temp_fixed |= 1 &amp;lt;&amp;lt; (src - 1);
+data-&amp;gt;reg_temp[0][src - 1] = reg_temp[i];
+data-&amp;gt;reg_temp[1][src - 1] = reg_temp_over[i];
+data-&amp;gt;reg_temp[2][src - 1] = reg_temp_hyst[i];
+data-&amp;gt;reg_temp_config[src - 1] = reg_temp_config[i];
+data-&amp;gt;temp_src[src - 1] = src;
+continue;
+}
+
+if (s &amp;gt;= NUM_TEMP)
+continue;
+
+/* Use dynamic index for other sources */
+data-&amp;gt;have_temp |= 1 &amp;lt;&amp;lt; s;
+data-&amp;gt;reg_temp[0][s] = reg_temp[i];
+data-&amp;gt;reg_temp[1][s] = reg_temp_over[i];
+data-&amp;gt;reg_temp[2][s] = reg_temp_hyst[i];
+data-&amp;gt;reg_temp_config[s] = reg_temp_config[i];
+if (reg_temp_crit[src - 1])
+data-&amp;gt;reg_temp[3][s] = reg_temp_crit[src - 1];
+
+data-&amp;gt;temp_src[s] = src;
+s++;
+}
+
+#ifdef TESTING
+/*
+ * Go through the list of alternate temp registers and enable
+ * if possible.
+ * The temperature is already monitored if the respective bit in &amp;lt;mask&amp;gt;
+ * is set.
+ */
+for (i = 0; i &amp;lt; data-&amp;gt;temp_label_num - 1; i++) {
+if (!reg_temp_alternate[i])
+continue;
+if (mask &amp;amp; (1 &amp;lt;&amp;lt; (i + 1)))
+continue;
+if (i &amp;lt; data-&amp;gt;temp_fixed_num) {
+if (data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i))
+continue;
+data-&amp;gt;have_temp |= 1 &amp;lt;&amp;lt; i;
+data-&amp;gt;have_temp_fixed |= 1 &amp;lt;&amp;lt; i;
+data-&amp;gt;reg_temp[0][i] = reg_temp_alternate[i];
+data-&amp;gt;reg_temp[1][i] = reg_temp_over[i];
+data-&amp;gt;reg_temp[2][i] = reg_temp_hyst[i];
+data-&amp;gt;temp_src[i] = i + 1;
+continue;
+}
+
+if (s &amp;gt;= NUM_TEMP)/* Abort if no more space */
+break;
+
+data-&amp;gt;have_temp |= 1 &amp;lt;&amp;lt; s;
+data-&amp;gt;reg_temp[0][s] = reg_temp_alternate[i];
+data-&amp;gt;temp_src[s] = i + 1;
+s++;
+}
+#endif /* TESTING */
+
+switch (data-&amp;gt;kind) {
+case nct6775:
+break;
+case 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-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; 2)) {
+u8 reg = nct6775_read_value(data,
+    data-&amp;gt;reg_temp_config[2]);
+if (reg &amp;amp; 0x01)
+data-&amp;gt;have_temp &amp;amp;= ~(1 &amp;lt;&amp;lt; 2);
+else
+data-&amp;gt;have_in &amp;amp;= ~(1 &amp;lt;&amp;lt; 6);
+}
+break;
+case nct6779:
+/*
+ * Shared pins:
+ *VIN4 / AUXTIN0
+ *VIN5 / AUXTIN1
+ *VIN6 / AUXTIN2
+ *VIN7 / AUXTIN3
+ *
+ * There does not seem to be a clean way to detect if VINx or
+ * AUXTINx is active, so for keep both sensor types enabled
+ * for now.
+ */
+break;
+}
+
+/* Initialize the chip */
+nct6775_init_device(data);
+
+data-&amp;gt;vrm = vid_which_vrm();
+superio_enter(sio_data-&amp;gt;sioreg);
+/*
+ * Read VID value
+ * We can get the VID input values directly at logical device D 0xe3.
+ */
+superio_select(sio_data-&amp;gt;sioreg, NCT6775_LD_VID);
+data-&amp;gt;vid = superio_inb(sio_data-&amp;gt;sioreg, 0xe3);
+
+if (fan_debounce) {
+u8 tmp;
+
+superio_select(sio_data-&amp;gt;sioreg, NCT6775_LD_HWM);
+tmp = superio_inb(sio_data-&amp;gt;sioreg,
+  NCT6775_REG_CR_FAN_DEBOUNCE);
+switch (data-&amp;gt;kind) {
+case nct6775:
+tmp |= 0x1e;
+break;
+case nct6776:
+case nct6779:
+tmp |= 0x3e;
+break;
+}
+superio_outb(sio_data-&amp;gt;sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
+     tmp);
+dev_info(&amp;amp;pdev-&amp;gt;dev, "Enabled fan debounce for chip %s\n",
+ data-&amp;gt;name);
+}
+
+superio_exit(sio_data-&amp;gt;sioreg);
+
+err = device_create_file(dev, &amp;amp;dev_attr_cpu0_vid);
+if (err)
+return err;
+
+nct6775_check_fan_inputs(sio_data, data);
+
+/* Read fan clock dividers immediately */
+nct6775_update_fan_div_common(dev, data);
+
+/* Register sysfs hooks */
+for (i = 0; i &amp;lt; data-&amp;gt;pwm_num; i++) {
+if (!(data-&amp;gt;has_pwm &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+
+err = sysfs_create_group(&amp;amp;dev-&amp;gt;kobj, &amp;amp;nct6775_group_pwm[i]);
+if (err)
+goto exit_remove;
+
+if (data-&amp;gt;REG_PWM[3]) {
+err = device_create_file(dev,
+&amp;amp;sda_max_output[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;REG_PWM[4]) {
+err = device_create_file(dev,
+&amp;amp;sda_step_output[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;REG_PWM[6]) {
+err = device_create_file(dev,
+&amp;amp;sda_weight_duty_base[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+}
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
+struct sensor_device_attribute_2 *attr =
+&amp;amp;sda_auto_pwm_arrays[i];
+
+if (!(data-&amp;gt;has_pwm &amp;amp; (1 &amp;lt;&amp;lt; attr-&amp;gt;nr)))
+continue;
+if (attr-&amp;gt;index &amp;gt; data-&amp;gt;auto_pwm_num)
+continue;
+err = device_create_file(dev, &amp;amp;attr-&amp;gt;dev_attr);
+if (err)
+goto exit_remove;
+}
+
+for (i = 0; i &amp;lt; data-&amp;gt;in_num; i++) {
+if (!(data-&amp;gt;have_in &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+err = sysfs_create_group(&amp;amp;dev-&amp;gt;kobj, &amp;amp;nct6775_group_in[i]);
+if (err)
+goto exit_remove;
+}
+
+for (i = 0; i &amp;lt; 5; i++) {
+if (data-&amp;gt;has_fan &amp;amp; (1 &amp;lt;&amp;lt; i)) {
+err = device_create_file(dev,
+ &amp;amp;sda_fan_input[i].dev_attr);
+if (err)
+goto exit_remove;
+err = device_create_file(dev,
+ &amp;amp;sda_fan_alarm[i].dev_attr);
+if (err)
+goto exit_remove;
+if (data-&amp;gt;kind != nct6776 &amp;amp;&amp;amp;
+    data-&amp;gt;kind != nct6779) {
+err = device_create_file(dev,
+&amp;amp;sda_fan_div[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;has_fan_min &amp;amp; (1 &amp;lt;&amp;lt; i)) {
+err = device_create_file(dev,
+&amp;amp;sda_fan_min[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+}
+}
+
+for (i = 0; i &amp;lt; NUM_TEMP; i++) {
+if (!(data-&amp;gt;have_temp &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+err = device_create_file(dev, &amp;amp;sda_temp_input[i].dev_attr);
+if (err)
+goto exit_remove;
+if (data-&amp;gt;temp_label) {
+err = device_create_file(dev,
+ &amp;amp;sda_temp_label[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;reg_temp[1][i]) {
+err = device_create_file(dev,
+ &amp;amp;sda_temp_max[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;reg_temp[2][i]) {
+err = device_create_file(dev,
+&amp;amp;sda_temp_max_hyst[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (data-&amp;gt;reg_temp[3][i]) {
+err = device_create_file(dev,
+ &amp;amp;sda_temp_crit[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+if (!(data-&amp;gt;have_temp_fixed &amp;amp; (1 &amp;lt;&amp;lt; i)))
+continue;
+err = device_create_file(dev, &amp;amp;sda_temp_type[i].dev_attr);
+if (err)
+goto exit_remove;
+err = device_create_file(dev, &amp;amp;sda_temp_offset[i].dev_attr);
+if (err)
+goto exit_remove;
+if (i &amp;gt;= NUM_TEMP_ALARM ||
+    data-&amp;gt;ALARM_BITS[TEMP_ALARM_BASE + i] &amp;lt; 0)
+continue;
+err = device_create_file(dev, &amp;amp;sda_temp_alarm[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+
+for (i = 0; i &amp;lt; ARRAY_SIZE(sda_caseopen); i++) {
+if (data-&amp;gt;ALARM_BITS[INTRUSION_ALARM_BASE + i] &amp;lt; 0)
+continue;
+err = device_create_file(dev, &amp;amp;sda_caseopen[i].dev_attr);
+if (err)
+goto exit_remove;
+}
+
+err = device_create_file(dev, &amp;amp;dev_attr_name);
+if (err)
+goto exit_remove;
+
+data-&amp;gt;hwmon_dev = hwmon_device_register(dev);
+if (IS_ERR(data-&amp;gt;hwmon_dev)) {
+err = PTR_ERR(data-&amp;gt;hwmon_dev);
+goto exit_remove;
+}
+
+return 0;
+
+exit_remove:
+nct6775_device_remove_files(dev);
+return err;
+}
+
+static int __devexit nct6775_remove(struct platform_device *pdev)
+{
+struct nct6775_data *data = platform_get_drvdata(pdev);
+
+hwmon_device_unregister(data-&amp;gt;hwmon_dev);
+nct6775_device_remove_files(&amp;amp;pdev-&amp;gt;dev);
+
+return 0;
+}
+
+static struct platform_driver nct6775_driver = {
+.driver = {
+.owner= THIS_MODULE,
+.name= DRVNAME,
+},
+.probe= nct6775_probe,
+.remove= __devexit_p(nct6775_remove),
+};
+
+/* nct6775_find() looks for a '627 in the Super-I/O config space */
+static int __init nct6775_find(int sioaddr, unsigned short *addr,
+       struct nct6775_sio_data *sio_data)
+{
+static const char __initdata sio_name_NCT6775[] = "NCT6775F";
+static const char __initdata sio_name_NCT6776[] = "NCT6776F";
+static const char __initdata sio_name_NCT6779[] = "NCT6779D";
+
+u16 val;
+const char *sio_name;
+
+superio_enter(sioaddr);
+
+if (force_id)
+val = force_id;
+else
+val = (superio_inb(sioaddr, SIO_REG_DEVID) &amp;lt;&amp;lt; 8)
+    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+switch (val &amp;amp; SIO_ID_MASK) {
+case SIO_NCT6775_ID:
+sio_data-&amp;gt;kind = nct6775;
+sio_name = sio_name_NCT6775;
+break;
+case SIO_NCT6776_ID:
+sio_data-&amp;gt;kind = nct6776;
+sio_name = sio_name_NCT6776;
+break;
+case SIO_NCT6779_ID:
+sio_data-&amp;gt;kind = nct6779;
+sio_name = sio_name_NCT6779;
+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) &amp;lt;&amp;lt; 8)
+    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+*addr = val &amp;amp; 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 &amp;amp; 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-&amp;gt;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 nct6775 driver. But since we platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev;
+
+static int __init sensors_nct6775_init(void)
+{
+int err;
+unsigned short address;
+struct resource res;
+struct nct6775_sio_data sio_data;
+
+/*
+ * initialize sio_data-&amp;gt;kind and sio_data-&amp;gt;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()
+ */
+if (nct6775_find(0x2e, &amp;amp;address, &amp;amp;sio_data) &amp;amp;&amp;amp;
+    nct6775_find(0x4e, &amp;amp;address, &amp;amp;sio_data))
+return -ENODEV;
+
+err = platform_driver_register(&amp;amp;nct6775_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, &amp;amp;sio_data,
+       sizeof(struct nct6775_sio_data));
+if (err) {
+pr_err("Platform data allocation failed\n");
+goto exit_device_put;
+}
+
+memset(&amp;amp;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(&amp;amp;res);
+if (err)
+goto exit_device_put;
+
+err = platform_device_add_resources(pdev, &amp;amp;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(&amp;amp;nct6775_driver);
+exit:
+return err;
+}
+
+static void __exit sensors_nct6775_exit(void)
+{
+platform_device_unregister(pdev);
+platform_driver_unregister(&amp;amp;nct6775_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;");
+MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6775_init);
+module_exit(sensors_nct6775_exit);
&lt;/pre&gt;</description>
    <dc:creator>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T02:40:31</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29701">
    <title>gelegenheit zur webverbesserung</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29701</link>
    <description>&lt;pre&gt;Hallo,

Mein Name ist Sven und ich bin der Webmaster von SEO DE.

Nebenbei arbeite ich auch f&amp;amp;uuml;r meine anderen Projekt-Webseiten und dadurch
stie&amp;amp;szlig; ich auf lists.lm-sensors.org und ich sch&amp;amp;auml;tze wirklich das gute Design und die Informationen.

Ich habe Seiten von sehr guter Qualit&amp;amp;auml;t , von wo aus Sie verlinkt w&amp;amp;uuml;rden.
Wie Sie vielleicht wissen, Links von guter Qualit&amp;amp;auml;t k&amp;amp;ouml;nnenauf jeden Fall
helfen beim Page Rank, Verkehr und bei h&amp;amp;ouml;herer Platzierung in den wichtigsten Suchmaschinen
wie Google, Yahoo und Bing.

Sollten Sie Interesse an weiteren Details haben, dann melden Sie sich bitte zur&amp;amp;uuml;ck bei mir
und ich werde Ihnen den perfekte Vorschlag f&amp;amp;uuml;r Ihre Website machen, der bei der Verbesserung
Ihrer Website in allen Aspektenhilft.

Hoffebaldvon Ihnen zu h&amp;amp;ouml;ren und einen sch&amp;amp;ouml;nen Tag w&amp;amp;uuml;nsche ich Ihnen

Mit freundlichen Gr&amp;amp;uuml;&amp;amp;szlig;en,

Sven Daffner
SEOde.org

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Sven Daffner</dc:creator>
    <dc:date>2012-05-21T03:01:36</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29699">
    <title>[PATCH] sensors-detect: Add detection of NCT6779D andNCT6102D/NCT6106D</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29699</link>
    <description>&lt;pre&gt;Signed-off-by: Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
---
 CHANGES                    |    1 +
 prog/detect/sensors-detect |   12 ++++++++++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/CHANGES b/CHANGES
index 615ed65..b08d205 100644
--- a/CHANGES
+++ b/CHANGES
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,6 +6,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; SVN HEAD
   sensors: Fix libiconv linkage need detection in rare corner case
   sensors-detect: Don't choke on systems without PCI
                   Avoid probing EDID addresses on graphics cards (#2386)
+  Add detection of NCT6779D and NCT6102D/NCT6106D
 
 3.3.2 (2012-03-14)
   libsensors: Added support for new sysfs attributes
diff --git a/prog/detect/sensors-detect b/prog/detect/sensors-detect
index 58f7fd0..6bfd1e2 100755
--- a/prog/detect/sensors-detect
+++ b/prog/detect/sensors-detect
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2034,6 +2034,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; use constant FEAT_SMBUS=&amp;gt; (1 &amp;lt;&amp;lt; 7);
 logdev =&amp;gt; 0x0b,
 features =&amp;gt; FEAT_IN | FEAT_FAN | FEAT_TEMP,
 }, {
+name =&amp;gt; "Nuvoton NCT6779D Super IO Sensors",
+driver =&amp;gt; "to-be-written",# nct6775, new driver
+devid =&amp;gt; 0xC562,
+logdev =&amp;gt; 0x0b,
+features =&amp;gt; FEAT_IN | FEAT_FAN | FEAT_TEMP,
+}, {
+name =&amp;gt; "Nuvoton NCT6102D/NCT6106D Super IO Sensors",
+driver =&amp;gt; "to-be-written",# nct6775, new driver
+devid =&amp;gt; 0x1061,
+logdev =&amp;gt; 0x0b,
+features =&amp;gt; FEAT_IN | FEAT_FAN | FEAT_TEMP,
+}, {
 name =&amp;gt; "Fintek F71805F/FG Super IO Sensors",
 driver =&amp;gt; "f71805f",
 devid =&amp;gt; 0x0406,
&lt;/pre&gt;</description>
    <dc:creator>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T00:59:36</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29696">
    <title>Fan control for Asus P8Z77</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29696</link>
    <description>&lt;pre&gt;Hi,

The (somewhat) new Asus P8Z77 boards have arrived, I'm wondering how the
status for fan control is for them?
I have a Asus P8Z77-V Pro, tried both it87 and asus_atk0110, both result in
that pwmconfig cannot find any controllable fans.

Currently running libsensors version 3.3.2+SVN. I'm up for testing any
patches related to this chipset.
_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Andrée 'Glaucous'</dc:creator>
    <dc:date>2012-05-20T17:19:46</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29694">
    <title>[PATCH 1/2] hwmon: (pmbus) Add support fornon-standard status register</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29694</link>
    <description>&lt;pre&gt;Not all PMBus devices support the byte status register at 0x78.
Add support for non-standard status registers to work around this problem.

Signed-off-by: Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
---
 drivers/hwmon/pmbus/pmbus.h      |    1 +
 drivers/hwmon/pmbus/pmbus_core.c |   13 +++++++++----
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 3fe03dc..8073dc4 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -332,6 +332,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct pmbus_driver_info {
 int R[PSC_NUM_CLASSES];/* exponent */
 
 u32 func[PMBUS_PAGES];/* Functionality, per page */
+u8 status_register;/* Set if not PMBUS_STATUS_BYTE */
 /*
  * The following functions map manufacturing specific register values
  * to PMBus standard register values. Specify only if mapping is
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 29b319d..0d8d50c 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -150,6 +150,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct pmbus_data {
  * so we keep them all together.
  */
 u8 status[PB_NUM_STATUS_REG];
+u8 status_register;
 
 u8 currpage;
 };
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -318,9 +319,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; EXPORT_SYMBOL_GPL(pmbus_clear_faults);
 
 static int pmbus_check_status_cml(struct i2c_client *client)
 {
+struct pmbus_data *data = i2c_get_clientdata(client);
 int status, status2;
 
-status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+status = _pmbus_read_byte_data(client, -1, data-&amp;gt;status_register);
 if (status &amp;lt; 0 || (status &amp;amp; PB_STATUS_CML)) {
 status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
 if (status2 &amp;lt; 0 || (status2 &amp;amp; PB_CML_FAULT_INVALID_COMMAND))
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -376,7 +378,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static struct pmbus_data *pmbus_update_device(struct device *dev)
 for (i = 0; i &amp;lt; info-&amp;gt;pages; i++)
 data-&amp;gt;status[PB_STATUS_BASE + i]
     = _pmbus_read_byte_data(client, i,
-    PMBUS_STATUS_BYTE);
+    data-&amp;gt;status_register);
 for (i = 0; i &amp;lt; info-&amp;gt;pages; i++) {
 if (!(info-&amp;gt;func[i] &amp;amp; PMBUS_HAVE_STATUS_VOUT))
 continue;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1069,7 +1071,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
  * the generic status register for this page is accessible.
  */
 if (!have_alarm &amp;amp;&amp;amp; attr-&amp;gt;gbit &amp;amp;&amp;amp;
-    pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
+    pmbus_check_byte_register(client, page,
+      data-&amp;gt;status_register))
 pmbus_add_boolean_reg(data, name, "alarm", index,
       PB_STATUS_BASE + page,
       attr-&amp;gt;gbit);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1704,8 +1707,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
 i2c_set_clientdata(client, data);
 mutex_init(&amp;amp;data-&amp;gt;update_lock);
 
+data-&amp;gt;status_register = info-&amp;gt;status_register ? : PMBUS_STATUS_BYTE;
+
 /* Bail out if PMBus status register does not exist. */
-if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) &amp;lt; 0) {
+if (i2c_smbus_read_byte_data(client, data-&amp;gt;status_register) &amp;lt; 0) {
 dev_err(&amp;amp;client-&amp;gt;dev, "PMBus status register not found\n");
 return -ENODEV;
 }
&lt;/pre&gt;</description>
    <dc:creator>Guenter Roeck</dc:creator>
    <dc:date>2012-05-19T18:48:19</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29687">
    <title>[SPAM:4.1] International Order</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29687</link>
    <description>&lt;pre&gt;
 Hello Sales
      I went over your contact online and found some items which we have interest in purchasing to our store in Spain for urgent supply. I will like to know the prices per each items plus the shipping cost. I Also want to know if Letter of Credit or T/T is acceptable for payment. I await your quick response asap so i can proceed with my needed items and quantity.

Thank you
Robertson Spencer


N.B.M Supply Inc
Address: Autovía A-5, 
salidas 22 y 26. 
Arroyomolinos, 
28939 Madrid Spain
Tel: +34 902 26 77 26
Email: robertsonspencer1&amp;lt; at &amp;gt;gmail.com
Website : http://www.brplastics.com



_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Robertson Spencer</dc:creator>
    <dc:date>2012-05-16T17:50:15</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29672">
    <title>[PATCH] hwmon: (it87) Drop uart6 condition forvin5&amp;vin6 for IT8783F</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29672</link>
    <description>&lt;pre&gt;From: Bjoern Gerhart &amp;lt;oss&amp;lt; at &amp;gt;extracloud.de&amp;gt;

Drop UART6 condition for IT8783F related to VIN5 and VIN6.
In case UART6 is routed via JP4 to a different set of pins,
VIN5 and VIN6 can be used at the same time.

diff -Naur a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
--- a/drivers/hwmon/it87.c2012-05-15 16:53:07.156061059 +0200
+++ b/drivers/hwmon/it87.c2012-05-15 17:19:31.717061875 +0200
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1806,11 +1806,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 sio_data-&amp;gt;skip_pwm |= (1 &amp;lt;&amp;lt; 1);
 
 /* VIN5 */
-if ((reg27 &amp;amp; (1 &amp;lt;&amp;lt; 0)) || uart6)
+if (reg27 &amp;amp; (1 &amp;lt;&amp;lt; 0))
 sio_data-&amp;gt;skip_in |= (1 &amp;lt;&amp;lt; 5); /* No VIN5 */
 
 /* VIN6 */
-if ((reg27 &amp;amp; (1 &amp;lt;&amp;lt; 1)) || uart6)
+if (reg27 &amp;amp; (1 &amp;lt;&amp;lt; 1))
 sio_data-&amp;gt;skip_in |= (1 &amp;lt;&amp;lt; 6); /* No VIN6 */
 
 /*



_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

&lt;/pre&gt;</description>
    <dc:creator>Björn Gerhart</dc:creator>
    <dc:date>2012-05-15T17:25:03</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29657">
    <title>HP  TONERS  Cartridge</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29657</link>
    <description>&lt;pre&gt;Can  you  send  me  the pricing  and  availablity  of this  product

 LASER JET PRINT CARTRIDGE, (OEM ONLY)
 HP LASER JET PRINT CARTRIDGE
 1Q6000A (OEM ONLY)
 2. HEWC9730A (30A) (OEM ONLY)
 3. HEWC9731A (31A) (OEM ONLY)
 4. Q5942A (42A)(OEM ONLY)
 5. HP Q7551A (51A)(OEM ONLY)
 6. HP Q3964A (64A) BLACK  COULOUR ONLY (OEM ONLY)
 7  HP    Q7553A 53A)  OEM ONLY
 8 NEW &amp;amp; USED, COMPUTERS  NOTEBOOK
9 USB  FLASH  DRIVES

 The mode of our  payment  is   with  our visa, master
 cards


Hope  to  read  from  you  asap
DAN RHODES
CA 90703





_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

&lt;/pre&gt;</description>
    <dc:creator>dan rhodes</dc:creator>
    <dc:date>2012-05-14T04:50:40</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29656">
    <title>Howto compile py-smbus with python 3.2</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29656</link>
    <description>&lt;pre&gt;Hello &amp;lt; at &amp;gt;All,

i try to compile i2c-tools-3.1.0 py-smbus, smbusmodule.c with the following command under Ubuntu 12.04:
python3.2 ./setup.py build

But it fail. With Python 2.7 it works.
Has onlybody a solution to use that module with python 3.2?

With kind regards
Bernhard
&lt;/pre&gt;</description>
    <dc:creator>Bernhard Renz</dc:creator>
    <dc:date>2012-05-14T08:36:47</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29652">
    <title>Community &amp; educational development</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29652</link>
    <description>&lt;pre&gt;PRESS RELEASE

The American Grants and Loans Catalog is now available. Our new and revised
2012 edition contains more than 2800 financial programs, subsidies, scholarships,
grants and loans offered by the US federal government.

In addition you will also have access to over 2400 programs funded by private
corporations and foundations. That is over 5200 programs available through
various sources of financial providing organizations.

NEW: You will also have access to our live Database that is updated on a daily
basis. This product also provides daily email alerts as programs are announced.

The Database is also available with IP recognition. This allows you to login
without a username or password (Great for libraries or educational institutions
who want their users to access the database).

Businesses, students, researchers, scientists, teachers, doctors, private individuals,
municipalities, government departments, educational institutions, law enforcement
agencies, nonprofits, foundations and associations will find a wealth of information
that will help them with their new ventures or existing projects.

The document is a fully searchable PDF file for easy access to your particular
needs and interests. Simply enter your keywords to search through the publication.

It is the perfect tool for libraries and educational institutions to use as a
reference guide for students who require funds to pursue their education.


Contents of the Directory:

-Web link to program announcement page
-Web link to Federal agency or foundation administering the program
-Authorization upon which a program is based
-Objectives and goals of the program
-Types of financial assistance offered under a program
-Uses and restrictions placed upon a program
-Eligibility requirements
-Application and award process
-Regulations, guidelines and literature relevant to a program
-Information contacts at the headquarters, regional, and local offices
-Programs that are related based upon program objectives and uses


Programs in the Catalog provide a wide range of benefits and services
for categories such as:

Agriculture
Business and Commerce
Community Development
Consumer Protection
Cultural Affairs
Disaster Prevention and Relief
Education
Employment, Labor and Training
Energy
Environmental Quality
Food and Nutrition
Health
Housing
Income Security and Social Services
Information and Statistics
Law, Justice, and Legal Services
Natural Resources
Regional Development
Science and Technology
Transportation


CD version: $69.95
Printed version: $149.95

To order please call: 1 (888) 341-8645


Please do not reply to the sender's email address as this address is only for outgoing mail.

If you do not wish to receive information from us in the future please reply here:
rem217&amp;lt; at &amp;gt;mail.com

This is a CANSPAM ACT compliant advertising broadcast sent by:
American Publishing Inc. , 7025 County Rd. 46A, Suite 1071, Lake Mary, FL, 32746-4753
_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>AP</dc:creator>
    <dc:date>2012-05-14T01:32:34</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29636">
    <title>missing fan RPMS</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29636</link>
    <description>&lt;pre&gt;
I bought a new motherboard (ASRock 970 Extreme3) and it doesn't report the fans.

# sensors-detect
Driver `adt7475':
  * Bus `nouveau-0000:01:00.0-2'
    Busdriver `drm', I2C address 0x2e
    Chip `Analog Devices ADT7473' (confidence: 5)

Driver `w83627ehf':
  * ISA bus, address 0x290
    Chip `Nuvoton NCT6776F Super IO Sensors' (confidence: 9)

Driver `fam15h_power':
  * Chip `AMD Family 15h power sensors' (confidence: 9)

Driver `k10temp':
  * Chip `AMD Family 15h thermal sensors' (confidence: 9)


# sensors            
nouveau-pci-0100
Adapter: PCI adapter
temp1:         +0.0 C  (high = +100.0 C, crit = +110.0 C)

fam15h_power-pci-00c4
Adapter: PCI adapter
power1:      101.61 W  (crit =  95.01 W)

k10temp-pci-00c3
Adapter: PCI adapter
temp1:        +15.8 C  (high = +70.0 C)
                       (crit = +70.0 C, hyst = +67.0 C)

nct6776-isa-0290
Adapter: ISA adapter
Vcore:        +0.86 V  (min =  +0.00 V, max =  +1.74 V)
in1:          +1.85 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
AVCC:         +3.33 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
+3.3V:        +3.33 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in4:          +1.58 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
in5:          +1.70 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
3VSB:         +3.44 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
Vbat:         +3.34 V  (min =  +0.00 V, max =  +0.00 V)  ALARM
fan1:           0 RPM  (min =    0 RPM)  ALARM
fan2:           0 RPM  (min =    0 RPM)  ALARM
fan3:           0 RPM  (min =    0 RPM)  ALARM
fan4:           0 RPM  (min =    0 RPM)  ALARM
fan5:           0 RPM  (min =    0 RPM)  ALARM
SYSTIN:       +38.0 C  (high =  +0.0 C, hyst =  +0.0 C)  ALARM  sensor = thermistor
CPUTIN:       +36.0 C  (high = +80.0 C, hyst = +75.0 C)  sensor = thermistor
AUXTIN:        -2.0 C  (high = +80.0 C, hyst = +75.0 C)  sensor = thermistor
cpu0_vid:    +0.000 V
intrusion0:  ALARM
intrusion1:  ALARM


The motherboard manual says it does the following hardware monitoring:
 CPU Temperature Sensing
 Chassis Temperature Sensing
 CPU/Chassis/Power Fan Tachometer
 CPU/Chassis Quiet Fan
 CPU/Chassis Fan Multi-Speed Control
 Voltage Monitoring: +12V, +5V, +3.3V, Vcore

The CPU fan says 3366 RPM in the BIOS.
Case fan3 1033 RPM.
sensors also doesn't show +12V or +5V.

_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

&lt;/pre&gt;</description>
    <dc:creator>James</dc:creator>
    <dc:date>2012-05-12T21:25:21</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29635">
    <title>[PATCH] hwmon: INA219 and INA226 support</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29635</link>
    <description>&lt;pre&gt;From: "Felten, Lothar" &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;

Add support for the Texas Instruments INA219 and INA226 power monitors.

Signed-off-by: Lothar Felten &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;
[guenter.roeck&amp;lt; at &amp;gt;ericsson.com: Cosmetic formatting changes]
Signed-off-by: Guenter Roeck &amp;lt;guenter.roeck&amp;lt; at &amp;gt;ericsson.com&amp;gt;
---
Just realized Lothar forgot to copy the list on this. So here it is.

 Documentation/hwmon/ina2xx           |   29 +++
 drivers/hwmon/Kconfig                |   13 ++
 drivers/hwmon/Makefile               |    1 +
 drivers/hwmon/ina2xx.c               |  368 ++++++++++++++++++++++++++++++++++
 include/linux/platform_data/ina2xx.h |   19 ++
 5 files changed, 430 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/hwmon/ina2xx
 create mode 100644 drivers/hwmon/ina2xx.c
 create mode 100644 include/linux/platform_data/ina2xx.h

diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
new file mode 100644
index 0000000..f50a6cc
--- /dev/null
+++ b/Documentation/hwmon/ina2xx
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+Kernel driver ina2xx
+====================
+
+Supported chips:
+  * Texas Instruments INA219
+    Prefix: 'ina219'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+  * Texas Instruments INA226
+    Prefix: 'ina226'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+Author: Lothar Felten &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;
+
+Description
+-----------
+
+The INA219 is a high-side current shunt and power monitor with an I2C
+interface. The INA219 monitors both shunt drop and supply voltage, with
+programmable conversion times and filtering.
+
+The INA226 is a current shunt and power monitor with an I2C interface.
+The INA226 monitors both a shunt voltage drop and bus supply voltage.
+
+The shunt value in micro-ohms can be set via platform data.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8deedc1..1c7bbd4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1102,6 +1102,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config SENSORS_AMC6821
   This driver can also be build as a module.  If so, the module
   will be called amc6821.
 
+config SENSORS_INA2XX
+tristate "Texas Instruments INA219, INA226"
+depends on I2C &amp;amp;&amp;amp; EXPERIMENTAL
+help
+  If you say yes here you get support for INA219 and INA226 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_THMC50
 tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6d3f11f..e1eeac1 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -62,6 +62,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; obj-$(CONFIG_SENSORS_ULTRA45)+= ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)+= ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)+= ibmpex.o
+obj-$(CONFIG_SENSORS_INA2XX)+= ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)+= it87.o
 obj-$(CONFIG_SENSORS_JC42)+= jc42.o
 obj-$(CONFIG_SENSORS_JZ4740)+= jz4740-hwmon.o
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 0000000..94a8743
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,368 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * 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
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * Copyright (C) 2012 Lothar Felten &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;
+ * 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 &amp;lt;linux/kernel.h&amp;gt;
+#include &amp;lt;linux/module.h&amp;gt;
+#include &amp;lt;linux/init.h&amp;gt;
+#include &amp;lt;linux/err.h&amp;gt;
+#include &amp;lt;linux/slab.h&amp;gt;
+#include &amp;lt;linux/i2c.h&amp;gt;
+#include &amp;lt;linux/hwmon.h&amp;gt;
+#include &amp;lt;linux/hwmon-sysfs.h&amp;gt;
+
+#include &amp;lt;linux/platform_data/ina2xx.h&amp;gt;
+
+/* common register definitions */
+#define INA2XX_CONFIG0x00
+#define INA2XX_SHUNT_VOLTAGE0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE0x02 /* readonly */
+#define INA2XX_POWER0x03 /* readonly */
+#define INA2XX_CURRENT0x04 /* readonly */
+#define INA2XX_CALIBRATION0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE0x06
+#define INA226_ALERT_LIMIT0x07
+#define INA226_DIE_ID0xFF
+
+
+/* register count */
+#define INA219_REGISTERS6
+#define INA226_REGISTERS8
+
+#define INA2XX_MAX_REGISTERS8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT0x219F/* PGA=1 */
+#define INA226_CONFIG_DEFAULT0x4527/* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE15
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_data {
+struct device *hwmon_dev;
+
+struct mutex update_lock;
+bool valid;
+unsigned long last_updated;
+
+int kind;
+int registers;
+u16 regs[INA2XX_MAX_REGISTERS];
+};
+
+int ina2xx_read_word(struct i2c_client *client, int reg)
+{
+int val = i2c_smbus_read_word_data(client, reg);
+if (unlikely(val &amp;lt; 0)) {
+dev_dbg(&amp;amp;client-&amp;gt;dev,
+"Failed to read register: %d\n", reg);
+return val;
+}
+return be16_to_cpu(val);
+}
+
+void ina2xx_write_word(struct i2c_client *client, int reg, int data)
+{
+i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+struct i2c_client *client = to_i2c_client(dev);
+struct ina2xx_data *data = i2c_get_clientdata(client);
+struct ina2xx_data *ret = data;
+
+mutex_lock(&amp;amp;data-&amp;gt;update_lock);
+
+if (time_after(jiffies, data-&amp;gt;last_updated +
+       HZ / INA2XX_CONVERSION_RATE) || !data-&amp;gt;valid) {
+
+int i;
+
+dev_dbg(&amp;amp;client-&amp;gt;dev, "Starting ina2xx update\n");
+
+/* Read all registers */
+for (i = 0; i &amp;lt; data-&amp;gt;registers; i++) {
+int rv = ina2xx_read_word(client, i);
+if (rv &amp;lt; 0) {
+ret = ERR_PTR(rv);
+goto abort;
+}
+data-&amp;gt;regs[i] = rv;
+}
+data-&amp;gt;last_updated = jiffies;
+data-&amp;gt;valid = 1;
+}
+abort:
+mutex_unlock(&amp;amp;data-&amp;gt;update_lock);
+return ret;
+}
+
+static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+{
+/*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 &amp;amp; 2 -&amp;gt; conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA219_CALIBRATION_VALUE
+ */
+int val = data-&amp;gt;regs[reg];
+
+switch (reg) {
+case INA2XX_SHUNT_VOLTAGE:
+/* LSB=10uV. Convert to mV. */
+val = DIV_ROUND_CLOSEST(val, 100);
+break;
+case INA2XX_BUS_VOLTAGE:
+/* LSB=4mV. Register is not right aligned, convert to mV. */
+val = (val &amp;gt;&amp;gt; 3) * 4;
+break;
+case INA2XX_POWER:
+/* LSB=20mW. Convert to uW */
+val = val * 20 * 1000;
+break;
+case INA2XX_CURRENT:
+/* LSB=1mA (selected). Is in mA */
+break;
+default:
+/* programmer goofed */
+WARN_ON_ONCE(1);
+val = 0;
+break;
+}
+
+return val;
+}
+
+static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+{
+/*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 &amp;amp; 2 -&amp;gt; conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA226_CALIBRATION_VALUE
+ */
+int val = data-&amp;gt;regs[reg];
+
+switch (reg) {
+case INA2XX_SHUNT_VOLTAGE:
+/* LSB=2.5uV. Convert to mV. */
+val = DIV_ROUND_CLOSEST(val, 400);
+break;
+case INA2XX_BUS_VOLTAGE:
+/* LSB=1.25mV. Convert to mV. */
+val = val + DIV_ROUND_CLOSEST(val, 4);
+break;
+case INA2XX_POWER:
+/* LSB=25mW. Convert to uW */
+val = val * 25 * 1000;
+break;
+case INA2XX_CURRENT:
+/* LSB=1mA (selected). Is in mA */
+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 = ina2xx_update_device(dev);
+int value = 0;
+
+if (IS_ERR(data))
+return PTR_ERR(data);
+
+switch (data-&amp;gt;kind) {
+case ina219:
+value = ina219_get_value(data, attr-&amp;gt;index);
+break;
+case ina226:
+value = ina226_get_value(data, attr-&amp;gt;index);
+break;
+default:
+WARN_ON_ONCE(1);
+break;
+}
+return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/* 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);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attributes[] = {
+&amp;amp;sensor_dev_attr_in0_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_in1_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_curr1_input.dev_attr.attr,
+&amp;amp;sensor_dev_attr_power1_input.dev_attr.attr,
+NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+.attrs = ina2xx_attributes,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+const struct i2c_device_id *id)
+{
+struct i2c_adapter *adapter = client-&amp;gt;adapter;
+struct ina2xx_data *data;
+struct ina2xx_platform_data *pdata;
+int ret = 0;
+long shunt = 10000; /* default shunt value 10mOhms */
+
+if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+return -ENODEV;
+
+data = devm_kzalloc(&amp;amp;client-&amp;gt;dev, sizeof(*data), GFP_KERNEL);
+if (!data)
+return -ENOMEM;
+
+if (client-&amp;gt;dev.platform_data) {
+pdata =
+  (struct ina2xx_platform_data *)client-&amp;gt;dev.platform_data;
+shunt = pdata-&amp;gt;shunt_uohms;
+}
+
+if (shunt &amp;lt;= 0)
+return -ENODEV;
+
+/* set the device type */
+data-&amp;gt;kind = id-&amp;gt;driver_data;
+
+switch (data-&amp;gt;kind) {
+case ina219:
+/* device configuration */
+ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+
+/* set current LSB to 1mA, shunt is in uOhms */
+/* (equation 13 in datasheet) */
+ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
+dev_info(&amp;amp;client-&amp;gt;dev,
+ "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
+data-&amp;gt;registers = INA219_REGISTERS;
+break;
+case ina226:
+/* device configuration */
+ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
+
+/* set current LSB to 1mA, shunt is in uOhms */
+/* (equation 1 in datasheet)*/
+ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
+dev_info(&amp;amp;client-&amp;gt;dev,
+ "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
+data-&amp;gt;registers = INA226_REGISTERS;
+break;
+default:
+/* unknown device id */
+return -ENODEV;
+}
+
+i2c_set_clientdata(client, data);
+mutex_init(&amp;amp;data-&amp;gt;update_lock);
+
+ret = sysfs_create_group(&amp;amp;client-&amp;gt;dev.kobj, &amp;amp;ina2xx_group);
+if (ret)
+return ret;
+
+data-&amp;gt;hwmon_dev = hwmon_device_register(&amp;amp;client-&amp;gt;dev);
+if (IS_ERR(data-&amp;gt;hwmon_dev)) {
+ret = PTR_ERR(data-&amp;gt;hwmon_dev);
+goto out_err_hwmon;
+}
+
+return 0;
+
+out_err_hwmon:
+sysfs_remove_group(&amp;amp;client-&amp;gt;dev.kobj, &amp;amp;ina2xx_group);
+return ret;
+}
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+struct ina2xx_data *data = i2c_get_clientdata(client);
+
+hwmon_device_unregister(data-&amp;gt;hwmon_dev);
+sysfs_remove_group(&amp;amp;client-&amp;gt;dev.kobj, &amp;amp;ina2xx_group);
+
+return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+{ "ina219", ina219 },
+{ "ina226", ina226 },
+{ }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+.driver = {
+.name= "ina2xx",
+},
+.probe= ina2xx_probe,
+.remove= ina2xx_remove,
+.id_table= ina2xx_id,
+};
+
+static int __init ina2xx_init(void)
+{
+return i2c_add_driver(&amp;amp;ina2xx_driver);
+}
+
+static void __exit ina2xx_exit(void)
+{
+i2c_del_driver(&amp;amp;ina2xx_driver);
+}
+
+MODULE_AUTHOR("Lothar Felten &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
+
+module_init(ina2xx_init);
+module_exit(ina2xx_exit);
diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h
new file mode 100644
index 0000000..9abc0ca
--- /dev/null
+++ b/include/linux/platform_data/ina2xx.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * Copyright (C) 2012 Lothar Felten &amp;lt;l-felten&amp;lt; at &amp;gt;ti.com&amp;gt;
+ *
+ * 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/ina2xx file.
+ */
+
+/**
+ * struct ina2xx_platform_data - ina2xx info
+ * &amp;lt; at &amp;gt;shunt_uohmsshunt resistance in microohms
+ */
+struct ina2xx_platform_data {
+long shunt_uohms;
+};
&lt;/pre&gt;</description>
    <dc:creator>Guenter Roeck</dc:creator>
    <dc:date>2012-05-12T19:50:18</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29624">
    <title>fancontrol and applesmc</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29624</link>
    <description>&lt;pre&gt;Hi,
i managed to get fancontrol to play nice with applesmc,
the only modification i had to make was to allow unbounded
PWM values (i basically removed the &amp;lt;= 255 condition, there
is still a small issue with pwmenable/disable functions).

That kind of fancontrol config works quite well :

DEVPATH=hwmon0=devices/platform/applesmc.768
DEVNAME=hwmon0=applesmc
INTERVAL=10
# fan1 : Optical Disk Drive, near GPU, temp15 : TG0D GPU Die
# fan2 : Hard Disk Drive, temp45 : Tp1P Power board
# fan3 : CPU, temp5 : TC0P CPU Proximity
FCTEMPS=hwmon0/device/fan1_min=hwmon0/device/temp15_input hwmon0/device/fan2_min=hwmon0/device/temp45_input hwmon0/device/fan3_min=hwmon0/device/temp5_input
FCFANS=hwmon0/device/fan1_min=hwmon0/device/fan1_output hwmon0/device/fan2_min=hwmon0/device/fan2_output hwmon0/device/fan3_min=hwmon0/device/fan3_output
MINPWM=hwmon0/device/fan1_min=100 hwmon0/device/fan2_min=100 hwmon0/device/fan3_min=800
MAXPWM=hwmon0/device/fan1_min=2100 hwmon0/device/fan2_min=5500 hwmon0/device/fan3_min=2500
MINTEMP=hwmon0/device/fan1_min=40 hwmon0/device/fan2_min=40 hwmon0/device/fan3_min=30
MAXTEMP=hwmon0/device/fan1_min=60 hwmon0/device/fan2_min=59 hwmon0/device/fan3_min=62
MINSTART=hwmon0/device/fan1_min=100 hwmon0/device/fan2_min=100 hwmon0/device/fan3_min=100
MINSTOP=hwmon0/device/fan1_min=100 hwmon0/device/fan2_min=100 hwmon0/device/fan3_min=800


Would a patch to fancontrol be welcome ?

Regards,
Jérémy.


_______________________________________________
lm-sensors mailing list
lm-sensors&amp;lt; at &amp;gt;lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors&lt;/pre&gt;</description>
    <dc:creator>Jérémy Lal</dc:creator>
    <dc:date>2012-05-11T22:27:07</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.drivers.sensors/29622">
    <title>[PATCH v2] hwmon: (it87) Convert to use devm_kzallocand devm_request_region</title>
    <link>http://comments.gmane.org/gmane.linux.drivers.sensors/29622</link>
    <description>&lt;pre&gt;From: Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;

This makes the code a bit simpler and smaller.

Signed-off-by: Guenter Roeck &amp;lt;linux&amp;lt; at &amp;gt;roeck-us.net&amp;gt;
---
v2: Also convert devm_request_region for further simplification

 drivers/hwmon/it87.c |   32 +++++++++-----------------------
 1 files changed, 9 insertions(+), 23 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e2e68eb..5f65fef 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1968,19 +1968,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit it87_probe(struct platform_device *pdev)
 };
 
 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-if (!request_region(res-&amp;gt;start, IT87_EC_EXTENT, DRVNAME)) {
+if (!devm_request_region(&amp;amp;pdev-&amp;gt;dev, res-&amp;gt;start, IT87_EC_EXTENT,
+ DRVNAME)) {
 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
 (unsigned long)res-&amp;gt;start,
 (unsigned long)(res-&amp;gt;start + IT87_EC_EXTENT - 1));
-err = -EBUSY;
-goto ERROR0;
+return -EBUSY;
 }
 
-data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
-if (!data) {
-err = -ENOMEM;
-goto ERROR1;
-}
+data = devm_kzalloc(&amp;amp;pdev-&amp;gt;dev, sizeof(struct it87_data), GFP_KERNEL);
+if (!data)
+return -ENOMEM;
 
 data-&amp;gt;addr = res-&amp;gt;start;
 data-&amp;gt;type = sio_data-&amp;gt;type;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1989,10 +1987,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit it87_probe(struct platform_device *pdev)
 
 /* Now, we do the remaining detection. */
 if ((it87_read_value(data, IT87_REG_CONFIG) &amp;amp; 0x80)
- || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
-err = -ENODEV;
-goto ERROR2;
-}
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+return -ENODEV;
 
 platform_set_drvdata(pdev, data);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2022,7 +2018,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit it87_probe(struct platform_device *pdev)
 /* Register sysfs hooks */
 err = sysfs_create_group(&amp;amp;dev-&amp;gt;kobj, &amp;amp;it87_group);
 if (err)
-goto ERROR2;
+return err;
 
 for (i = 0; i &amp;lt; 9; i++) {
 if (sio_data-&amp;gt;skip_in &amp;amp; (1 &amp;lt;&amp;lt; i))
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2123,12 +2119,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit it87_probe(struct platform_device *pdev)
 
 ERROR4:
 it87_remove_files(dev);
-ERROR2:
-platform_set_drvdata(pdev, NULL);
-kfree(data);
-ERROR1:
-release_region(res-&amp;gt;start, IT87_EC_EXTENT);
-ERROR0:
 return err;
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2139,10 +2129,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devexit it87_remove(struct platform_device *pdev)
 hwmon_device_unregister(data-&amp;gt;hwmon_dev);
 it87_remove_files(&amp;amp;pdev-&amp;gt;dev);
 
-release_region(data-&amp;gt;addr, IT87_EC_EXTENT);
-platform_set_drvdata(pdev, NULL);
-kfree(data);
-
 return 0;
 }
 
&lt;/pre&gt;</description>
    <dc:creator>Guenter Roeck</dc:creator>
    <dc:date>2012-05-11T21:42:32</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.linux.drivers.sensors">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.linux.drivers.sensors</link>
  </textinput>
</rdf:RDF>

