<?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://permalink.gmane.org/gmane.linux.drivers.sensors/29717"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29716"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29715"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29714"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29713"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29712"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29711"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29709"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29708"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29707"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29706"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29705"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29704"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29703"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29702"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29701"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29700"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29699"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29698"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.drivers.sensors/29697"/>
      </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://permalink.gmane.org/gmane.linux.drivers.sensors/29717">
    <title>rocky hu与您共享了照片</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29716">
    <title>[patch] watchdog: sch56xx-common: set correct bits inregister()</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29715">
    <title>Re: Nuvoton NCT6776D - AsRock</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29715</link>
    <description>&lt;pre&gt;Hi,

that really depends on your kernel version. Try "modprobe w83627ehf".

There is an experimental driver at https://github.com/groeck/nct6775
which you can try as well. It has somewhat improved fan control support.

There is one caveat, though - AsRock uses a GPIO based multiplexer to
map multiple fans into a single fan speed input of the NCT6776F chip. As
a result, you won't be able to see (or control) the speed of all fans.

Guenter



_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-23T16:39:19</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29714">
    <title>Nuvoton NCT6776D - AsRock</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29713">
    <title>Re: ASUS Sabertooth Z77 / nct6775.ko report</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29713</link>
    <description>&lt;pre&gt;Hi Dmitriy,

thanks a lot for the feedback.


The NCT6779D has only five fan sensors, so that is not surprising. Maybe
the other fans are not monitored, there is a second chip to
control/monitor the other fans, or ASUS started putting a multiplexer at
the fan inputs. I hope they didn't, but maybe they learned the wrong
lesson from AsusTek.


No idea what is happening here. The temperature values are taken
directly from the chip registers. ASUS might have a another chip to
monitor other temperatures. Interesting that the PECI input is not
shown; it is used on all other ASUS boards I have seen.


Frankly, I have never seen useful output from this. No idea if it is
even connected.


This is quite common; limits are rarely programmed by BIOSes for some
reason. You'll have to set the limits yourself. The alarms will go away
if the limits are set.

Sounds good. Can you provide output of
"grep . /sys/devices/platform/nct6775.656/pwm*" and "sensors -u" ?

Not much I can do right now. A complete register dump would help, but I
don't know how to do that in Linux. I'll may have to start extending
superiotool to support the chip, but that will take some time, which I
don't have right now :(.

Guenter



_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-23T15:33:34</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29712">
    <title>lavoriamo insieme</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29711">
    <title>ASUS Sabertooth Z77 / nct6775.ko report</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29709">
    <title>Re: [PATCH] hwmon: INA219 and INA226 support</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29709</link>
    <description>&lt;pre&gt;Ok, I updated that in the pending patch.

Thanks,
Guenter

_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-22T13:47:57</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29708">
    <title>Re: [PATCH] hwmon: INA219 and INA226 support</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29708</link>
    <description>&lt;pre&gt;Hi Guenter,


No there was no special reason, the default setting after reset is PGA=8, this
Is probably the best selection. So that should be:
#define INA219_CONFIG_DEFAULT          0x399F  /* default values */

INA2XX_SHUNT_VOLTAGE will then go from -320mV to +320mV, that should be ok.


Best regards,
Lothar




Texas Instruments Belgium SA, Rond Point Schuman 6– Boîte 5, 1040 Bruxelles. BCE: 0414.207.123. RPM Bruxelles. IBAN: BE83570121895615. Swift: CITIBEBX. TVA BE 0414.207.123


_______________________________________________
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>Felten, Lothar</dc:creator>
    <dc:date>2012-05-22T07:13:35</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29707">
    <title>Re: ASRock 970 Extreme3</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29707</link>
    <description>&lt;pre&gt;
I really don't know details. Supposedly there is a .xml file somewhere
in the ASRock software describing which connector is connected to which
fan, and which fans are multiplexed. The NCT6776F has up to 5 fan
inputs, so theoretically you could get up to 5 fans working. But then I
have no idea which header connects to which fan input, and which headers
are multiplexed.

Guenter



_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T20:15:58</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29706">
    <title>Re: ASRock 970 Extreme3</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29706</link>
    <description>&lt;pre&gt;It looks like I can get two fans.
So can I assume that there are two sensors for the 6 connectors and 3 are multiplexed for each sensor?
Is it correct that there are GPIO pins to switch which fan the sensor reads from?

_______________________________________________
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-21T20:07:01</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29705">
    <title>Re: ASRock 970 Extreme3</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29705</link>
    <description>&lt;pre&gt;
Problem is that ASRock uses a GPIO based multiplexer to connect the
fans. So there is no 1:1 relationship between fans connectors and fan
attributes. The GPIO pins used vary from board to board.

There are some possibilities to support this, such as to modify the
fancontrol script to also support setting gpio pins (if there is a gpio
driver for the given HW), or to somehow implement the necessary support
in the kernel. But those are all not really good solutions, and there
are some questions if it can be made to work reliably in the first
place. The AIDA64 folks tried to implement it but gave up (see
http://forums.aida64.com/index.php?/topic/386-asrocks-fan-controller-sensor-trouble/), which is not a good sign.

Guenter



_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T18:11:30</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29704">
    <title>ASRock 970 Extreme3</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29703">
    <title>Re: [PATCH] hwmon: INA219 and INA226 support</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29703</link>
    <description>&lt;pre&gt;Hi Lothar,

On Tue, 2012-05-08 at 13:43 -0400, Felten, Lothar wrote:
I have a couple of observations.

[ ... ]


[ ... ]

With this configuration (PGA=1), the dynamic range for the shunt
resistor voltage is 40 mV. Since we report the value in mV, it does not
provide much value to do that. It might be better to use PGA=8 instead,
for a dynamic range of 320 mV.

Did you have a special reason for selecting PGA=1 ? Otherwise, I think
we should change it to PGA=8.

[ ... ]


This is actually wrong; we need to check for I2C_FUNC_SMBUS_WORD_DATA
instead. I fixed that already.

Thanks,
Guenter



_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T16:44:23</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29702">
    <title>[PATCH] hwmon: Driver for Nuvoton NCT6775F, NCT6776F,and NCT6779D</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29701">
    <title>gelegenheit zur webverbesserung</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29700">
    <title>Re: Fan control for Asus P8Z77</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29700</link>
    <description>&lt;pre&gt;Please don't top-post.

Looks like it is time to submit the driver for review so it can make it into the kernel.

Guenter


_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-21T01:08:26</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29699">
    <title>[PATCH] sensors-detect: Add detection of NCT6779D andNCT6102D/NCT6106D</title>
    <link>http://permalink.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://permalink.gmane.org/gmane.linux.drivers.sensors/29698">
    <title>Re: Fan control for Asus P8Z77</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29698</link>
    <description>&lt;pre&gt;Indeed, after an hour of searching around I actually found that
experimental driver.
I can confirm that it works very well!

On 20 May 2012 21:21, Guenter Roeck &amp;lt;guenter.roeck&amp;lt; at &amp;gt;ericsson.com&amp;gt; wrote:

_______________________________________________
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-20T20:30:27</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29697">
    <title>Re: Fan control for Asus P8Z77</title>
    <link>http://permalink.gmane.org/gmane.linux.drivers.sensors/29697</link>
    <description>&lt;pre&gt;
Are you sure the board uses an IT87xx ? As far as I know, it uses NCT6779D.

For NCT6779D, you can find an experimental driver at https://github.com/groeck/nct6775.

Thanks,
Guenter

_______________________________________________
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>Guenter Roeck</dc:creator>
    <dc:date>2012-05-20T19:21:00</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.drivers.sensors/29696">
    <title>Fan control for Asus P8Z77</title>
    <link>http://permalink.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>
  <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>

