xref: /openbmc/linux/drivers/hwmon/nct6775-core.c (revision 3b7f4bde06daaff391a374fc27c8163b2847de34)
1c3963bc0SZev Weiss // SPDX-License-Identifier: GPL-2.0-or-later
2c3963bc0SZev Weiss /*
3c3963bc0SZev Weiss  * nct6775 - Driver for the hardware monitoring functionality of
4c3963bc0SZev Weiss  *	       Nuvoton NCT677x Super-I/O chips
5c3963bc0SZev Weiss  *
6c3963bc0SZev Weiss  * Copyright (C) 2012  Guenter Roeck <linux@roeck-us.net>
7c3963bc0SZev Weiss  *
8c3963bc0SZev Weiss  * Derived from w83627ehf driver
9c3963bc0SZev Weiss  * Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
10c3963bc0SZev Weiss  * Copyright (C) 2006  Yuan Mu (Winbond),
11c3963bc0SZev Weiss  *		       Rudolf Marek <r.marek@assembler.cz>
12c3963bc0SZev Weiss  *		       David Hubbard <david.c.hubbard@gmail.com>
13c3963bc0SZev Weiss  *		       Daniel J Blueman <daniel.blueman@gmail.com>
14c3963bc0SZev Weiss  * Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
15c3963bc0SZev Weiss  *
16c3963bc0SZev Weiss  * Shamelessly ripped from the w83627hf driver
17c3963bc0SZev Weiss  * Copyright (C) 2003  Mark Studebaker
18c3963bc0SZev Weiss  *
19c3963bc0SZev Weiss  * Supports the following chips:
20c3963bc0SZev Weiss  *
21c3963bc0SZev Weiss  * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
22c3963bc0SZev Weiss  * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
23c3963bc0SZev Weiss  * nct6116d     9      5       5       3+3    0xd280 0xc1    0x5ca3
24c3963bc0SZev Weiss  * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
25c3963bc0SZev Weiss  * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
26c3963bc0SZev Weiss  * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
27c3963bc0SZev Weiss  * nct6791d    15      6       6       2+6    0xc800 0xc1    0x5ca3
28c3963bc0SZev Weiss  * nct6792d    15      6       6       2+6    0xc910 0xc1    0x5ca3
29c3963bc0SZev Weiss  * nct6793d    15      6       6       2+6    0xd120 0xc1    0x5ca3
30c3963bc0SZev Weiss  * nct6795d    14      6       6       2+6    0xd350 0xc1    0x5ca3
31c3963bc0SZev Weiss  * nct6796d    14      7       7       2+6    0xd420 0xc1    0x5ca3
32c3963bc0SZev Weiss  * nct6797d    14      7       7       2+6    0xd450 0xc1    0x5ca3
33c3963bc0SZev Weiss  *                                           (0xd451)
34c3963bc0SZev Weiss  * nct6798d    14      7       7       2+6    0xd428 0xc1    0x5ca3
35c3963bc0SZev Weiss  *                                           (0xd429)
3623299bbaSAhmad Khalifa  * nct6796d-s  18      7       7       6+2    0xd801 0xc1    0x5ca3
3723299bbaSAhmad Khalifa  * nct6799d-r  18      7       7       6+2    0xd802 0xc1    0x5ca3
38c3963bc0SZev Weiss  *
39c3963bc0SZev Weiss  * #temp lists the number of monitored temperature sources (first value) plus
40c3963bc0SZev Weiss  * the number of directly connectable temperature sensors (second value).
41c3963bc0SZev Weiss  */
42c3963bc0SZev Weiss 
43c3963bc0SZev Weiss #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
44c3963bc0SZev Weiss 
45c3963bc0SZev Weiss #include <linux/module.h>
46c3963bc0SZev Weiss #include <linux/init.h>
47c3963bc0SZev Weiss #include <linux/slab.h>
48c3963bc0SZev Weiss #include <linux/jiffies.h>
49c3963bc0SZev Weiss #include <linux/hwmon.h>
50c3963bc0SZev Weiss #include <linux/hwmon-sysfs.h>
51c3963bc0SZev Weiss #include <linux/err.h>
52c3963bc0SZev Weiss #include <linux/mutex.h>
53c3963bc0SZev Weiss #include <linux/bitops.h>
54c3963bc0SZev Weiss #include <linux/nospec.h>
55c3963bc0SZev Weiss #include <linux/regmap.h>
56c3963bc0SZev Weiss #include "lm75.h"
57c3963bc0SZev Weiss #include "nct6775.h"
58c3963bc0SZev Weiss 
59c3963bc0SZev Weiss #undef DEFAULT_SYMBOL_NAMESPACE
60c3963bc0SZev Weiss #define DEFAULT_SYMBOL_NAMESPACE HWMON_NCT6775
61c3963bc0SZev Weiss 
62c3963bc0SZev Weiss #define USE_ALTERNATE
63c3963bc0SZev Weiss 
64c3963bc0SZev Weiss /* used to set data->name = nct6775_device_names[data->sio_kind] */
65c3963bc0SZev Weiss static const char * const nct6775_device_names[] = {
66c3963bc0SZev Weiss 	"nct6106",
67c3963bc0SZev Weiss 	"nct6116",
68c3963bc0SZev Weiss 	"nct6775",
69c3963bc0SZev Weiss 	"nct6776",
70c3963bc0SZev Weiss 	"nct6779",
71c3963bc0SZev Weiss 	"nct6791",
72c3963bc0SZev Weiss 	"nct6792",
73c3963bc0SZev Weiss 	"nct6793",
74c3963bc0SZev Weiss 	"nct6795",
75c3963bc0SZev Weiss 	"nct6796",
76c3963bc0SZev Weiss 	"nct6797",
77c3963bc0SZev Weiss 	"nct6798",
78aee395bbSGuenter Roeck 	"nct6799",
79c3963bc0SZev Weiss };
80c3963bc0SZev Weiss 
81c3963bc0SZev Weiss /* Common and NCT6775 specific data */
82c3963bc0SZev Weiss 
83c3963bc0SZev Weiss /* Voltage min/max registers for nr=7..14 are in bank 5 */
84c3963bc0SZev Weiss 
85c3963bc0SZev Weiss static const u16 NCT6775_REG_IN_MAX[] = {
86c3963bc0SZev Weiss 	0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
87c3963bc0SZev Weiss 	0x55c, 0x55e, 0x560, 0x562 };
88c3963bc0SZev Weiss static const u16 NCT6775_REG_IN_MIN[] = {
89c3963bc0SZev Weiss 	0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
90c3963bc0SZev Weiss 	0x55d, 0x55f, 0x561, 0x563 };
91c3963bc0SZev Weiss static const u16 NCT6775_REG_IN[] = {
92c3963bc0SZev Weiss 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
93c3963bc0SZev Weiss };
94c3963bc0SZev Weiss 
95c3963bc0SZev Weiss #define NCT6775_REG_VBAT		0x5D
96c3963bc0SZev Weiss #define NCT6775_REG_DIODE		0x5E
97c3963bc0SZev Weiss #define NCT6775_DIODE_MASK		0x02
98c3963bc0SZev Weiss 
99c3963bc0SZev Weiss static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
100c3963bc0SZev Weiss 
101*3b7f4bdeSAhmad Khalifa static const s8 NCT6775_ALARM_BITS[NUM_ALARM_BITS] = {
102*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  8, 21, 20, 16, 17, -1, -1, -1,	  /* in0-in11     */
103*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
104*3b7f4bdeSAhmad Khalifa 	 6,  7, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
105*3b7f4bdeSAhmad Khalifa 	 4,  5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
106*3b7f4bdeSAhmad Khalifa 	12, -1,						  /* intr0-intr1  */
107*3b7f4bdeSAhmad Khalifa };
108c3963bc0SZev Weiss 
109c3963bc0SZev Weiss static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
110c3963bc0SZev Weiss 
111*3b7f4bdeSAhmad Khalifa static const s8 NCT6775_BEEP_BITS[NUM_BEEP_BITS] = {
112*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  8,  9, 10, 16, 17, -1, -1, -1,	  /* in0-in11     */
113*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
114*3b7f4bdeSAhmad Khalifa 	 6,  7, 11, 28, -1, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
115*3b7f4bdeSAhmad Khalifa 	 4,  5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
116*3b7f4bdeSAhmad Khalifa 	12, -1, 21					  /* intr0-intr1, beep_en */
117*3b7f4bdeSAhmad Khalifa };
118c3963bc0SZev Weiss 
119c3963bc0SZev Weiss /* DC or PWM output fan configuration */
120c3963bc0SZev Weiss static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
121c3963bc0SZev Weiss static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
122c3963bc0SZev Weiss 
123c3963bc0SZev Weiss /* Advanced Fan control, some values are common for all fans */
124c3963bc0SZev Weiss 
125c3963bc0SZev Weiss static const u16 NCT6775_REG_TARGET[] = {
126c3963bc0SZev Weiss 	0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
127c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MODE[] = {
128c3963bc0SZev Weiss 	0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
129c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
130c3963bc0SZev Weiss 	0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
131c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
132c3963bc0SZev Weiss 	0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
133c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
134c3963bc0SZev Weiss 	0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
135c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
136c3963bc0SZev Weiss 	0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
137c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
138c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
139c3963bc0SZev Weiss 
140c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
141c3963bc0SZev Weiss 	0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
142c3963bc0SZev Weiss static const u16 NCT6775_REG_PWM[] = {
143c3963bc0SZev Weiss 	0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
144c3963bc0SZev Weiss static const u16 NCT6775_REG_PWM_READ[] = {
145c3963bc0SZev Weiss 	0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
146c3963bc0SZev Weiss 
147c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
148c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
149c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = {
150c3963bc0SZev Weiss 	0x641, 0x642, 0x643, 0x644 };
151c3963bc0SZev Weiss static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { };
152c3963bc0SZev Weiss 
153c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP[] = {
154c3963bc0SZev Weiss 	0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
155c3963bc0SZev Weiss 
156c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
157c3963bc0SZev Weiss 
158c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
159c3963bc0SZev Weiss 	0, 0x152, 0x252, 0x628, 0x629, 0x62A };
160c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
161c3963bc0SZev Weiss 	0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
162c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
163c3963bc0SZev Weiss 	0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
164c3963bc0SZev Weiss 
165c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
166c3963bc0SZev Weiss 	0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
167c3963bc0SZev Weiss 
168c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_SEL[] = {
169c3963bc0SZev Weiss 	0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
170c3963bc0SZev Weiss 
171c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
172c3963bc0SZev Weiss 	0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
173c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
174c3963bc0SZev Weiss 	0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
175c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
176c3963bc0SZev Weiss 	0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
177c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
178c3963bc0SZev Weiss 	0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
179c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
180c3963bc0SZev Weiss 	0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
181c3963bc0SZev Weiss 
182c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
183c3963bc0SZev Weiss 
184c3963bc0SZev Weiss static const u16 NCT6775_REG_AUTO_TEMP[] = {
185c3963bc0SZev Weiss 	0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
186c3963bc0SZev Weiss static const u16 NCT6775_REG_AUTO_PWM[] = {
187c3963bc0SZev Weiss 	0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
188c3963bc0SZev Weiss 
189c3963bc0SZev Weiss #define NCT6775_AUTO_TEMP(data, nr, p)	((data)->REG_AUTO_TEMP[nr] + (p))
190c3963bc0SZev Weiss #define NCT6775_AUTO_PWM(data, nr, p)	((data)->REG_AUTO_PWM[nr] + (p))
191c3963bc0SZev Weiss 
192c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
193c3963bc0SZev Weiss 
194c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
195c3963bc0SZev Weiss 	0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
196c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
197c3963bc0SZev Weiss 	0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
198c3963bc0SZev Weiss 
199c3963bc0SZev Weiss static const char *const nct6775_temp_label[] = {
200c3963bc0SZev Weiss 	"",
201c3963bc0SZev Weiss 	"SYSTIN",
202c3963bc0SZev Weiss 	"CPUTIN",
203c3963bc0SZev Weiss 	"AUXTIN",
204c3963bc0SZev Weiss 	"AMD SB-TSI",
205c3963bc0SZev Weiss 	"PECI Agent 0",
206c3963bc0SZev Weiss 	"PECI Agent 1",
207c3963bc0SZev Weiss 	"PECI Agent 2",
208c3963bc0SZev Weiss 	"PECI Agent 3",
209c3963bc0SZev Weiss 	"PECI Agent 4",
210c3963bc0SZev Weiss 	"PECI Agent 5",
211c3963bc0SZev Weiss 	"PECI Agent 6",
212c3963bc0SZev Weiss 	"PECI Agent 7",
213c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
214c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
215c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
216c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
217c3963bc0SZev Weiss 	"PCH_DIM0_TEMP",
218c3963bc0SZev Weiss 	"PCH_DIM1_TEMP",
219c3963bc0SZev Weiss 	"PCH_DIM2_TEMP",
220c3963bc0SZev Weiss 	"PCH_DIM3_TEMP"
221c3963bc0SZev Weiss };
222c3963bc0SZev Weiss 
223c3963bc0SZev Weiss #define NCT6775_TEMP_MASK	0x001ffffe
224c3963bc0SZev Weiss #define NCT6775_VIRT_TEMP_MASK	0x00000000
225c3963bc0SZev Weiss 
226c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
227c3963bc0SZev Weiss 	[13] = 0x661,
228c3963bc0SZev Weiss 	[14] = 0x662,
229c3963bc0SZev Weiss 	[15] = 0x664,
230c3963bc0SZev Weiss };
231c3963bc0SZev Weiss 
232c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_CRIT[32] = {
233c3963bc0SZev Weiss 	[4] = 0xa00,
234c3963bc0SZev Weiss 	[5] = 0xa01,
235c3963bc0SZev Weiss 	[6] = 0xa02,
236c3963bc0SZev Weiss 	[7] = 0xa03,
237c3963bc0SZev Weiss 	[8] = 0xa04,
238c3963bc0SZev Weiss 	[9] = 0xa05,
239c3963bc0SZev Weiss 	[10] = 0xa06,
240c3963bc0SZev Weiss 	[11] = 0xa07
241c3963bc0SZev Weiss };
242c3963bc0SZev Weiss 
243c3963bc0SZev Weiss static const u16 NCT6775_REG_TSI_TEMP[] = { 0x669 };
244c3963bc0SZev Weiss 
245c3963bc0SZev Weiss /* NCT6776 specific data */
246c3963bc0SZev Weiss 
247c3963bc0SZev Weiss /* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
248c3963bc0SZev Weiss #define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
249c3963bc0SZev Weiss #define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
250c3963bc0SZev Weiss 
251*3b7f4bdeSAhmad Khalifa static const s8 NCT6776_ALARM_BITS[NUM_ALARM_BITS] = {
252*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  8, 21, 20, 16, 17, -1, -1, -1,	  /* in0-in11     */
253*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
254*3b7f4bdeSAhmad Khalifa 	 6,  7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
255*3b7f4bdeSAhmad Khalifa 	 4,  5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
256*3b7f4bdeSAhmad Khalifa 	12,  9,						  /* intr0-intr1  */
257*3b7f4bdeSAhmad Khalifa };
258c3963bc0SZev Weiss 
259c3963bc0SZev Weiss static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
260c3963bc0SZev Weiss 
261*3b7f4bdeSAhmad Khalifa static const s8 NCT6776_BEEP_BITS[NUM_BEEP_BITS] = {
262*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  6,  7,  8, -1, -1, -1,	  /* in0-in11     */
263*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
264*3b7f4bdeSAhmad Khalifa 	25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
265*3b7f4bdeSAhmad Khalifa 	16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
266*3b7f4bdeSAhmad Khalifa 	30, 31, 24					  /* intr0-intr1, beep_en */
267*3b7f4bdeSAhmad Khalifa };
268c3963bc0SZev Weiss 
269c3963bc0SZev Weiss static const u16 NCT6776_REG_TOLERANCE_H[] = {
270c3963bc0SZev Weiss 	0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
271c3963bc0SZev Weiss 
272c3963bc0SZev Weiss static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
273c3963bc0SZev Weiss static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
274c3963bc0SZev Weiss 
275c3963bc0SZev Weiss static const u16 NCT6776_REG_FAN_MIN[] = {
276c3963bc0SZev Weiss 	0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
277c3963bc0SZev Weiss static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = {
278c3963bc0SZev Weiss 	0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
279c3963bc0SZev Weiss 
280c3963bc0SZev Weiss static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
281c3963bc0SZev Weiss 	0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
282c3963bc0SZev Weiss 
283c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
284c3963bc0SZev Weiss 	0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
285c3963bc0SZev Weiss 
286c3963bc0SZev Weiss static const char *const nct6776_temp_label[] = {
287c3963bc0SZev Weiss 	"",
288c3963bc0SZev Weiss 	"SYSTIN",
289c3963bc0SZev Weiss 	"CPUTIN",
290c3963bc0SZev Weiss 	"AUXTIN",
291c3963bc0SZev Weiss 	"SMBUSMASTER 0",
292c3963bc0SZev Weiss 	"SMBUSMASTER 1",
293c3963bc0SZev Weiss 	"SMBUSMASTER 2",
294c3963bc0SZev Weiss 	"SMBUSMASTER 3",
295c3963bc0SZev Weiss 	"SMBUSMASTER 4",
296c3963bc0SZev Weiss 	"SMBUSMASTER 5",
297c3963bc0SZev Weiss 	"SMBUSMASTER 6",
298c3963bc0SZev Weiss 	"SMBUSMASTER 7",
299c3963bc0SZev Weiss 	"PECI Agent 0",
300c3963bc0SZev Weiss 	"PECI Agent 1",
301c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
302c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
303c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
304c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
305c3963bc0SZev Weiss 	"PCH_DIM0_TEMP",
306c3963bc0SZev Weiss 	"PCH_DIM1_TEMP",
307c3963bc0SZev Weiss 	"PCH_DIM2_TEMP",
308c3963bc0SZev Weiss 	"PCH_DIM3_TEMP",
309c3963bc0SZev Weiss 	"BYTE_TEMP"
310c3963bc0SZev Weiss };
311c3963bc0SZev Weiss 
312c3963bc0SZev Weiss #define NCT6776_TEMP_MASK	0x007ffffe
313c3963bc0SZev Weiss #define NCT6776_VIRT_TEMP_MASK	0x00000000
314c3963bc0SZev Weiss 
315c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
316c3963bc0SZev Weiss 	[14] = 0x401,
317c3963bc0SZev Weiss 	[15] = 0x402,
318c3963bc0SZev Weiss 	[16] = 0x404,
319c3963bc0SZev Weiss };
320c3963bc0SZev Weiss 
321c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_CRIT[32] = {
322c3963bc0SZev Weiss 	[11] = 0x709,
323c3963bc0SZev Weiss 	[12] = 0x70a,
324c3963bc0SZev Weiss };
325c3963bc0SZev Weiss 
326c3963bc0SZev Weiss static const u16 NCT6776_REG_TSI_TEMP[] = {
327c3963bc0SZev Weiss 	0x409, 0x40b, 0x40d, 0x40f, 0x411, 0x413, 0x415, 0x417 };
328c3963bc0SZev Weiss 
329c3963bc0SZev Weiss /* NCT6779 specific data */
330c3963bc0SZev Weiss 
331c3963bc0SZev Weiss static const u16 NCT6779_REG_IN[] = {
332c3963bc0SZev Weiss 	0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
333c3963bc0SZev Weiss 	0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
334c3963bc0SZev Weiss 
335c3963bc0SZev Weiss static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
336c3963bc0SZev Weiss 	0x459, 0x45A, 0x45B, 0x568 };
337c3963bc0SZev Weiss 
338*3b7f4bdeSAhmad Khalifa static const s8 NCT6779_ALARM_BITS[NUM_ALARM_BITS] = {
339*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  8, 21, 20, 16, 17, 24, 25, 26,	  /* in0-in11     */
340*3b7f4bdeSAhmad Khalifa 	27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
341*3b7f4bdeSAhmad Khalifa 	 6,  7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
342*3b7f4bdeSAhmad Khalifa 	 4,  5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
343*3b7f4bdeSAhmad Khalifa 	12,  9,						  /* intr0-intr1  */
344*3b7f4bdeSAhmad Khalifa };
345c3963bc0SZev Weiss 
346*3b7f4bdeSAhmad Khalifa static const s8 NCT6779_BEEP_BITS[NUM_BEEP_BITS] = {
347*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,	  /* in0-in11     */
348*3b7f4bdeSAhmad Khalifa 	12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
349*3b7f4bdeSAhmad Khalifa 	25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
350*3b7f4bdeSAhmad Khalifa 	16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
351*3b7f4bdeSAhmad Khalifa 	30, 31, 24					  /* intr0-intr1, beep_en */
352*3b7f4bdeSAhmad Khalifa };
353c3963bc0SZev Weiss 
354c3963bc0SZev Weiss static const u16 NCT6779_REG_FAN[] = {
355c3963bc0SZev Weiss 	0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
356c3963bc0SZev Weiss static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
357c3963bc0SZev Weiss 	0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
358c3963bc0SZev Weiss 
359c3963bc0SZev Weiss static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
360c3963bc0SZev Weiss 	0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
361c3963bc0SZev Weiss #define NCT6779_CRITICAL_PWM_ENABLE_MASK	0x01
362c3963bc0SZev Weiss static const u16 NCT6779_REG_CRITICAL_PWM[] = {
363c3963bc0SZev Weiss 	0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
364c3963bc0SZev Weiss 
365c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
366c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
367c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
368c3963bc0SZev Weiss 	0x18, 0x152 };
369c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
370c3963bc0SZev Weiss 	0x3a, 0x153 };
371c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
372c3963bc0SZev Weiss 	0x39, 0x155 };
373c3963bc0SZev Weiss 
374c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_OFFSET[] = {
375aee395bbSGuenter Roeck 	0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c, 0x44d, 0x449 };
376c3963bc0SZev Weiss 
377c3963bc0SZev Weiss static const char *const nct6779_temp_label[] = {
378c3963bc0SZev Weiss 	"",
379c3963bc0SZev Weiss 	"SYSTIN",
380c3963bc0SZev Weiss 	"CPUTIN",
381c3963bc0SZev Weiss 	"AUXTIN0",
382c3963bc0SZev Weiss 	"AUXTIN1",
383c3963bc0SZev Weiss 	"AUXTIN2",
384c3963bc0SZev Weiss 	"AUXTIN3",
385c3963bc0SZev Weiss 	"",
386c3963bc0SZev Weiss 	"SMBUSMASTER 0",
387c3963bc0SZev Weiss 	"SMBUSMASTER 1",
388c3963bc0SZev Weiss 	"SMBUSMASTER 2",
389c3963bc0SZev Weiss 	"SMBUSMASTER 3",
390c3963bc0SZev Weiss 	"SMBUSMASTER 4",
391c3963bc0SZev Weiss 	"SMBUSMASTER 5",
392c3963bc0SZev Weiss 	"SMBUSMASTER 6",
393c3963bc0SZev Weiss 	"SMBUSMASTER 7",
394c3963bc0SZev Weiss 	"PECI Agent 0",
395c3963bc0SZev Weiss 	"PECI Agent 1",
396c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
397c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
398c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
399c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
400c3963bc0SZev Weiss 	"PCH_DIM0_TEMP",
401c3963bc0SZev Weiss 	"PCH_DIM1_TEMP",
402c3963bc0SZev Weiss 	"PCH_DIM2_TEMP",
403c3963bc0SZev Weiss 	"PCH_DIM3_TEMP",
404c3963bc0SZev Weiss 	"BYTE_TEMP",
405c3963bc0SZev Weiss 	"",
406c3963bc0SZev Weiss 	"",
407c3963bc0SZev Weiss 	"",
408c3963bc0SZev Weiss 	"",
409c3963bc0SZev Weiss 	"Virtual_TEMP"
410c3963bc0SZev Weiss };
411c3963bc0SZev Weiss 
412c3963bc0SZev Weiss #define NCT6779_TEMP_MASK	0x07ffff7e
413c3963bc0SZev Weiss #define NCT6779_VIRT_TEMP_MASK	0x00000000
414c3963bc0SZev Weiss #define NCT6791_TEMP_MASK	0x87ffff7e
415c3963bc0SZev Weiss #define NCT6791_VIRT_TEMP_MASK	0x80000000
416c3963bc0SZev Weiss 
417c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
418c3963bc0SZev Weiss 	= { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
419c3963bc0SZev Weiss 	    0, 0, 0, 0, 0, 0, 0, 0,
420c3963bc0SZev Weiss 	    0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
421c3963bc0SZev Weiss 	    0x408, 0 };
422c3963bc0SZev Weiss 
423c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_CRIT[32] = {
424c3963bc0SZev Weiss 	[15] = 0x709,
425c3963bc0SZev Weiss 	[16] = 0x70a,
426c3963bc0SZev Weiss };
427c3963bc0SZev Weiss 
428c3963bc0SZev Weiss /* NCT6791 specific data */
429c3963bc0SZev Weiss 
430c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
431c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
432c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
433c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
434c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
435c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
436c3963bc0SZev Weiss 
437c3963bc0SZev Weiss static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
438c3963bc0SZev Weiss 	0x459, 0x45A, 0x45B, 0x568, 0x45D };
439c3963bc0SZev Weiss 
440*3b7f4bdeSAhmad Khalifa static const s8 NCT6791_ALARM_BITS[NUM_ALARM_BITS] = {
441*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  8, 21, 20, 16, 17, 24, 25, 26,	  /* in0-in11     */
442*3b7f4bdeSAhmad Khalifa 	27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
443*3b7f4bdeSAhmad Khalifa 	 6,  7, 11, 10, 23, 33, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
444*3b7f4bdeSAhmad Khalifa 	 4,  5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
445*3b7f4bdeSAhmad Khalifa 	12,  9,						  /* intr0-intr1  */
446*3b7f4bdeSAhmad Khalifa };
447c3963bc0SZev Weiss 
448c3963bc0SZev Weiss /* NCT6792/NCT6793 specific data */
449c3963bc0SZev Weiss 
450c3963bc0SZev Weiss static const u16 NCT6792_REG_TEMP_MON[] = {
451c3963bc0SZev Weiss 	0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
452c3963bc0SZev Weiss static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
453c3963bc0SZev Weiss 	0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
454c3963bc0SZev Weiss 
455c3963bc0SZev Weiss static const char *const nct6792_temp_label[] = {
456c3963bc0SZev Weiss 	"",
457c3963bc0SZev Weiss 	"SYSTIN",
458c3963bc0SZev Weiss 	"CPUTIN",
459c3963bc0SZev Weiss 	"AUXTIN0",
460c3963bc0SZev Weiss 	"AUXTIN1",
461c3963bc0SZev Weiss 	"AUXTIN2",
462c3963bc0SZev Weiss 	"AUXTIN3",
463c3963bc0SZev Weiss 	"",
464c3963bc0SZev Weiss 	"SMBUSMASTER 0",
465c3963bc0SZev Weiss 	"SMBUSMASTER 1",
466c3963bc0SZev Weiss 	"SMBUSMASTER 2",
467c3963bc0SZev Weiss 	"SMBUSMASTER 3",
468c3963bc0SZev Weiss 	"SMBUSMASTER 4",
469c3963bc0SZev Weiss 	"SMBUSMASTER 5",
470c3963bc0SZev Weiss 	"SMBUSMASTER 6",
471c3963bc0SZev Weiss 	"SMBUSMASTER 7",
472c3963bc0SZev Weiss 	"PECI Agent 0",
473c3963bc0SZev Weiss 	"PECI Agent 1",
474c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
475c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
476c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
477c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
478c3963bc0SZev Weiss 	"PCH_DIM0_TEMP",
479c3963bc0SZev Weiss 	"PCH_DIM1_TEMP",
480c3963bc0SZev Weiss 	"PCH_DIM2_TEMP",
481c3963bc0SZev Weiss 	"PCH_DIM3_TEMP",
482c3963bc0SZev Weiss 	"BYTE_TEMP",
483c3963bc0SZev Weiss 	"PECI Agent 0 Calibration",
484c3963bc0SZev Weiss 	"PECI Agent 1 Calibration",
485c3963bc0SZev Weiss 	"",
486c3963bc0SZev Weiss 	"",
487c3963bc0SZev Weiss 	"Virtual_TEMP"
488c3963bc0SZev Weiss };
489c3963bc0SZev Weiss 
490c3963bc0SZev Weiss #define NCT6792_TEMP_MASK	0x9fffff7e
491c3963bc0SZev Weiss #define NCT6792_VIRT_TEMP_MASK	0x80000000
492c3963bc0SZev Weiss 
493c3963bc0SZev Weiss static const char *const nct6793_temp_label[] = {
494c3963bc0SZev Weiss 	"",
495c3963bc0SZev Weiss 	"SYSTIN",
496c3963bc0SZev Weiss 	"CPUTIN",
497c3963bc0SZev Weiss 	"AUXTIN0",
498c3963bc0SZev Weiss 	"AUXTIN1",
499c3963bc0SZev Weiss 	"AUXTIN2",
500c3963bc0SZev Weiss 	"AUXTIN3",
501c3963bc0SZev Weiss 	"",
502c3963bc0SZev Weiss 	"SMBUSMASTER 0",
503c3963bc0SZev Weiss 	"SMBUSMASTER 1",
504c3963bc0SZev Weiss 	"",
505c3963bc0SZev Weiss 	"",
506c3963bc0SZev Weiss 	"",
507c3963bc0SZev Weiss 	"",
508c3963bc0SZev Weiss 	"",
509c3963bc0SZev Weiss 	"",
510c3963bc0SZev Weiss 	"PECI Agent 0",
511c3963bc0SZev Weiss 	"PECI Agent 1",
512c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
513c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
514c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
515c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
516c3963bc0SZev Weiss 	"Agent0 Dimm0 ",
517c3963bc0SZev Weiss 	"Agent0 Dimm1",
518c3963bc0SZev Weiss 	"Agent1 Dimm0",
519c3963bc0SZev Weiss 	"Agent1 Dimm1",
520c3963bc0SZev Weiss 	"BYTE_TEMP0",
521c3963bc0SZev Weiss 	"BYTE_TEMP1",
522c3963bc0SZev Weiss 	"PECI Agent 0 Calibration",
523c3963bc0SZev Weiss 	"PECI Agent 1 Calibration",
524c3963bc0SZev Weiss 	"",
525c3963bc0SZev Weiss 	"Virtual_TEMP"
526c3963bc0SZev Weiss };
527c3963bc0SZev Weiss 
528c3963bc0SZev Weiss #define NCT6793_TEMP_MASK	0xbfff037e
529c3963bc0SZev Weiss #define NCT6793_VIRT_TEMP_MASK	0x80000000
530c3963bc0SZev Weiss 
531c3963bc0SZev Weiss static const char *const nct6795_temp_label[] = {
532c3963bc0SZev Weiss 	"",
533c3963bc0SZev Weiss 	"SYSTIN",
534c3963bc0SZev Weiss 	"CPUTIN",
535c3963bc0SZev Weiss 	"AUXTIN0",
536c3963bc0SZev Weiss 	"AUXTIN1",
537c3963bc0SZev Weiss 	"AUXTIN2",
538c3963bc0SZev Weiss 	"AUXTIN3",
539c3963bc0SZev Weiss 	"",
540c3963bc0SZev Weiss 	"SMBUSMASTER 0",
541c3963bc0SZev Weiss 	"SMBUSMASTER 1",
542c3963bc0SZev Weiss 	"SMBUSMASTER 2",
543c3963bc0SZev Weiss 	"SMBUSMASTER 3",
544c3963bc0SZev Weiss 	"SMBUSMASTER 4",
545c3963bc0SZev Weiss 	"SMBUSMASTER 5",
546c3963bc0SZev Weiss 	"SMBUSMASTER 6",
547c3963bc0SZev Weiss 	"SMBUSMASTER 7",
548c3963bc0SZev Weiss 	"PECI Agent 0",
549c3963bc0SZev Weiss 	"PECI Agent 1",
550c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
551c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
552c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
553c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
554c3963bc0SZev Weiss 	"Agent0 Dimm0",
555c3963bc0SZev Weiss 	"Agent0 Dimm1",
556c3963bc0SZev Weiss 	"Agent1 Dimm0",
557c3963bc0SZev Weiss 	"Agent1 Dimm1",
558c3963bc0SZev Weiss 	"BYTE_TEMP0",
559c3963bc0SZev Weiss 	"BYTE_TEMP1",
560c3963bc0SZev Weiss 	"PECI Agent 0 Calibration",
561c3963bc0SZev Weiss 	"PECI Agent 1 Calibration",
562c3963bc0SZev Weiss 	"",
563c3963bc0SZev Weiss 	"Virtual_TEMP"
564c3963bc0SZev Weiss };
565c3963bc0SZev Weiss 
566c3963bc0SZev Weiss #define NCT6795_TEMP_MASK	0xbfffff7e
567c3963bc0SZev Weiss #define NCT6795_VIRT_TEMP_MASK	0x80000000
568c3963bc0SZev Weiss 
569c3963bc0SZev Weiss static const char *const nct6796_temp_label[] = {
570c3963bc0SZev Weiss 	"",
571c3963bc0SZev Weiss 	"SYSTIN",
572c3963bc0SZev Weiss 	"CPUTIN",
573c3963bc0SZev Weiss 	"AUXTIN0",
574c3963bc0SZev Weiss 	"AUXTIN1",
575c3963bc0SZev Weiss 	"AUXTIN2",
576c3963bc0SZev Weiss 	"AUXTIN3",
577c3963bc0SZev Weiss 	"AUXTIN4",
578c3963bc0SZev Weiss 	"SMBUSMASTER 0",
579c3963bc0SZev Weiss 	"SMBUSMASTER 1",
580c3963bc0SZev Weiss 	"Virtual_TEMP",
581c3963bc0SZev Weiss 	"Virtual_TEMP",
582c3963bc0SZev Weiss 	"",
583c3963bc0SZev Weiss 	"",
584c3963bc0SZev Weiss 	"",
585c3963bc0SZev Weiss 	"",
586c3963bc0SZev Weiss 	"PECI Agent 0",
587c3963bc0SZev Weiss 	"PECI Agent 1",
588c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
589c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
590c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
591c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
592c3963bc0SZev Weiss 	"Agent0 Dimm0",
593c3963bc0SZev Weiss 	"Agent0 Dimm1",
594c3963bc0SZev Weiss 	"Agent1 Dimm0",
595c3963bc0SZev Weiss 	"Agent1 Dimm1",
596c3963bc0SZev Weiss 	"BYTE_TEMP0",
597c3963bc0SZev Weiss 	"BYTE_TEMP1",
598c3963bc0SZev Weiss 	"PECI Agent 0 Calibration",
599c3963bc0SZev Weiss 	"PECI Agent 1 Calibration",
600c3963bc0SZev Weiss 	"",
601c3963bc0SZev Weiss 	"Virtual_TEMP"
602c3963bc0SZev Weiss };
603c3963bc0SZev Weiss 
604c3963bc0SZev Weiss #define NCT6796_TEMP_MASK	0xbfff0ffe
605c3963bc0SZev Weiss #define NCT6796_VIRT_TEMP_MASK	0x80000c00
606c3963bc0SZev Weiss 
607c3963bc0SZev Weiss static const u16 NCT6796_REG_TSI_TEMP[] = { 0x409, 0x40b };
608c3963bc0SZev Weiss 
609c3963bc0SZev Weiss static const char *const nct6798_temp_label[] = {
610c3963bc0SZev Weiss 	"",
611c3963bc0SZev Weiss 	"SYSTIN",
612c3963bc0SZev Weiss 	"CPUTIN",
613c3963bc0SZev Weiss 	"AUXTIN0",
614c3963bc0SZev Weiss 	"AUXTIN1",
615c3963bc0SZev Weiss 	"AUXTIN2",
616c3963bc0SZev Weiss 	"AUXTIN3",
617c3963bc0SZev Weiss 	"AUXTIN4",
618c3963bc0SZev Weiss 	"SMBUSMASTER 0",
619c3963bc0SZev Weiss 	"SMBUSMASTER 1",
620c3963bc0SZev Weiss 	"Virtual_TEMP",
621c3963bc0SZev Weiss 	"Virtual_TEMP",
622c3963bc0SZev Weiss 	"",
623c3963bc0SZev Weiss 	"",
624c3963bc0SZev Weiss 	"",
625c3963bc0SZev Weiss 	"",
626c3963bc0SZev Weiss 	"PECI Agent 0",
627c3963bc0SZev Weiss 	"PECI Agent 1",
628c3963bc0SZev Weiss 	"PCH_CHIP_CPU_MAX_TEMP",
629c3963bc0SZev Weiss 	"PCH_CHIP_TEMP",
630c3963bc0SZev Weiss 	"PCH_CPU_TEMP",
631c3963bc0SZev Weiss 	"PCH_MCH_TEMP",
632c3963bc0SZev Weiss 	"Agent0 Dimm0",
633c3963bc0SZev Weiss 	"Agent0 Dimm1",
634c3963bc0SZev Weiss 	"Agent1 Dimm0",
635c3963bc0SZev Weiss 	"Agent1 Dimm1",
636c3963bc0SZev Weiss 	"BYTE_TEMP0",
637c3963bc0SZev Weiss 	"BYTE_TEMP1",
638c3963bc0SZev Weiss 	"PECI Agent 0 Calibration",	/* undocumented */
639c3963bc0SZev Weiss 	"PECI Agent 1 Calibration",	/* undocumented */
640c3963bc0SZev Weiss 	"",
641c3963bc0SZev Weiss 	"Virtual_TEMP"
642c3963bc0SZev Weiss };
643c3963bc0SZev Weiss 
644c3963bc0SZev Weiss #define NCT6798_TEMP_MASK	0xbfff0ffe
645c3963bc0SZev Weiss #define NCT6798_VIRT_TEMP_MASK	0x80000c00
646c3963bc0SZev Weiss 
647aee395bbSGuenter Roeck static const char *const nct6799_temp_label[] = {
648aee395bbSGuenter Roeck 	"",
649aee395bbSGuenter Roeck 	"SYSTIN",
650aee395bbSGuenter Roeck 	"CPUTIN",
651aee395bbSGuenter Roeck 	"AUXTIN0",
652aee395bbSGuenter Roeck 	"AUXTIN1",
653aee395bbSGuenter Roeck 	"AUXTIN2",
654aee395bbSGuenter Roeck 	"AUXTIN3",
655aee395bbSGuenter Roeck 	"AUXTIN4",
656aee395bbSGuenter Roeck 	"SMBUSMASTER 0",
657aee395bbSGuenter Roeck 	"SMBUSMASTER 1",
658aee395bbSGuenter Roeck 	"Virtual_TEMP",
659aee395bbSGuenter Roeck 	"Virtual_TEMP",
660aee395bbSGuenter Roeck 	"",
661aee395bbSGuenter Roeck 	"AUXTIN5",
662aee395bbSGuenter Roeck 	"",
663aee395bbSGuenter Roeck 	"",
664aee395bbSGuenter Roeck 	"PECI Agent 0",
665aee395bbSGuenter Roeck 	"PECI Agent 1",
666aee395bbSGuenter Roeck 	"PCH_CHIP_CPU_MAX_TEMP",
667aee395bbSGuenter Roeck 	"PCH_CHIP_TEMP",
668aee395bbSGuenter Roeck 	"PCH_CPU_TEMP",
669aee395bbSGuenter Roeck 	"PCH_MCH_TEMP",
670aee395bbSGuenter Roeck 	"Agent0 Dimm0",
671aee395bbSGuenter Roeck 	"Agent0 Dimm1",
672aee395bbSGuenter Roeck 	"Agent1 Dimm0",
673aee395bbSGuenter Roeck 	"Agent1 Dimm1",
674aee395bbSGuenter Roeck 	"BYTE_TEMP0",
675aee395bbSGuenter Roeck 	"BYTE_TEMP1",
676aee395bbSGuenter Roeck 	"PECI Agent 0 Calibration",	/* undocumented */
677aee395bbSGuenter Roeck 	"PECI Agent 1 Calibration",	/* undocumented */
678aee395bbSGuenter Roeck 	"",
679aee395bbSGuenter Roeck 	"Virtual_TEMP"
680aee395bbSGuenter Roeck };
681aee395bbSGuenter Roeck 
682aee395bbSGuenter Roeck #define NCT6799_TEMP_MASK	0xbfff2ffe
683aee395bbSGuenter Roeck #define NCT6799_VIRT_TEMP_MASK	0x80000c00
684aee395bbSGuenter Roeck 
685c3963bc0SZev Weiss /* NCT6102D/NCT6106D specific data */
686c3963bc0SZev Weiss 
687c3963bc0SZev Weiss #define NCT6106_REG_VBAT	0x318
688c3963bc0SZev Weiss #define NCT6106_REG_DIODE	0x319
689c3963bc0SZev Weiss #define NCT6106_DIODE_MASK	0x01
690c3963bc0SZev Weiss 
691c3963bc0SZev Weiss static const u16 NCT6106_REG_IN_MAX[] = {
692c3963bc0SZev Weiss 	0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
693c3963bc0SZev Weiss static const u16 NCT6106_REG_IN_MIN[] = {
694c3963bc0SZev Weiss 	0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
695c3963bc0SZev Weiss static const u16 NCT6106_REG_IN[] = {
696c3963bc0SZev Weiss 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
697c3963bc0SZev Weiss 
698c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
699c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
700c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_HYST[] = {
701c3963bc0SZev Weiss 	0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
702c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_OVER[] = {
703c3963bc0SZev Weiss 	0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
704c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
705c3963bc0SZev Weiss 	0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
706c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
707c3963bc0SZev Weiss 	0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
708c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
709c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CONFIG[] = {
710c3963bc0SZev Weiss 	0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
711c3963bc0SZev Weiss 
712c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
713c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
714c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 };
715c3963bc0SZev Weiss static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
716c3963bc0SZev Weiss 
717c3963bc0SZev Weiss static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
718c3963bc0SZev Weiss static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
719c3963bc0SZev Weiss static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
720c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
721c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_SOURCE[] = {
722c3963bc0SZev Weiss 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
723c3963bc0SZev Weiss 
724c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
725c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
726c3963bc0SZev Weiss 	0x11b, 0x12b, 0x13b };
727c3963bc0SZev Weiss 
728c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
729c3963bc0SZev Weiss #define NCT6106_CRITICAL_PWM_ENABLE_MASK	0x10
730c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
731c3963bc0SZev Weiss 
732c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
733c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
734c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
735c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
736c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
737c3963bc0SZev Weiss static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
738c3963bc0SZev Weiss 
739c3963bc0SZev Weiss static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
740c3963bc0SZev Weiss 
741c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
742c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
743c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
744c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
745c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
746c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
747c3963bc0SZev Weiss 
748c3963bc0SZev Weiss static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
749c3963bc0SZev Weiss static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
750c3963bc0SZev Weiss 
751c3963bc0SZev Weiss static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
752c3963bc0SZev Weiss 	0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
753c3963bc0SZev Weiss 
754*3b7f4bdeSAhmad Khalifa static const s8 NCT6106_ALARM_BITS[NUM_ALARM_BITS] = {
755*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  7,  8,  9, -1, -1, -1,	  /* in0-in11     */
756*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
757*3b7f4bdeSAhmad Khalifa 	32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
758*3b7f4bdeSAhmad Khalifa 	16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
759*3b7f4bdeSAhmad Khalifa 	48, -1,						  /* intr0-intr1  */
760c3963bc0SZev Weiss };
761c3963bc0SZev Weiss 
762c3963bc0SZev Weiss static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
763c3963bc0SZev Weiss 	0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
764c3963bc0SZev Weiss 
765*3b7f4bdeSAhmad Khalifa static const s8 NCT6106_BEEP_BITS[NUM_BEEP_BITS] = {
766*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  7,  8,  9, 10, 11, 12,	  /* in0-in11     */
767*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
768*3b7f4bdeSAhmad Khalifa 	24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
769*3b7f4bdeSAhmad Khalifa 	16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
770*3b7f4bdeSAhmad Khalifa 	34, -1, 32					  /* intr0-intr1, beep_en */
771c3963bc0SZev Weiss };
772c3963bc0SZev Weiss 
773c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
774c3963bc0SZev Weiss 	[14] = 0x51,
775c3963bc0SZev Weiss 	[15] = 0x52,
776c3963bc0SZev Weiss 	[16] = 0x54,
777c3963bc0SZev Weiss };
778c3963bc0SZev Weiss 
779c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT[32] = {
780c3963bc0SZev Weiss 	[11] = 0x204,
781c3963bc0SZev Weiss 	[12] = 0x205,
782c3963bc0SZev Weiss };
783c3963bc0SZev Weiss 
784c3963bc0SZev Weiss static const u16 NCT6106_REG_TSI_TEMP[] = { 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65, 0x67 };
785c3963bc0SZev Weiss 
786c3963bc0SZev Weiss /* NCT6112D/NCT6114D/NCT6116D specific data */
787c3963bc0SZev Weiss 
788c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
789c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
790c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
791c3963bc0SZev Weiss static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
792c3963bc0SZev Weiss 
793c3963bc0SZev Weiss static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
794c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
795c3963bc0SZev Weiss static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
796c3963bc0SZev Weiss static const u16 NCT6116_REG_TEMP_SOURCE[] = {
797c3963bc0SZev Weiss 	0xb0, 0xb1, 0xb2 };
798c3963bc0SZev Weiss 
799c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
800c3963bc0SZev Weiss 	0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
801c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
802c3963bc0SZev Weiss 	0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
803c3963bc0SZev Weiss 
804c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
805c3963bc0SZev Weiss 	0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
806c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_PWM[] = {
807c3963bc0SZev Weiss 	0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
808c3963bc0SZev Weiss 
809c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
810c3963bc0SZev Weiss 	0x114, 0x124, 0x134, 0x194, 0x1a4 };
811c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
812c3963bc0SZev Weiss 	0x115, 0x125, 0x135, 0x195, 0x1a5 };
813c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
814c3963bc0SZev Weiss 	0x116, 0x126, 0x136, 0x196, 0x1a6 };
815c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
816c3963bc0SZev Weiss 	0x117, 0x127, 0x137, 0x197, 0x1a7 };
817c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
818c3963bc0SZev Weiss 	0x118, 0x128, 0x138, 0x198, 0x1a8 };
819c3963bc0SZev Weiss static const u16 NCT6116_REG_TOLERANCE_H[] = {
820c3963bc0SZev Weiss 	0x112, 0x122, 0x132, 0x192, 0x1a2 };
821c3963bc0SZev Weiss 
822c3963bc0SZev Weiss static const u16 NCT6116_REG_TARGET[] = {
823c3963bc0SZev Weiss 	0x111, 0x121, 0x131, 0x191, 0x1a1 };
824c3963bc0SZev Weiss 
825c3963bc0SZev Weiss static const u16 NCT6116_REG_AUTO_TEMP[] = {
826c3963bc0SZev Weiss 	0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
827c3963bc0SZev Weiss static const u16 NCT6116_REG_AUTO_PWM[] = {
828c3963bc0SZev Weiss 	0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
829c3963bc0SZev Weiss 
830*3b7f4bdeSAhmad Khalifa static const s8 NCT6116_ALARM_BITS[NUM_ALARM_BITS] = {
831*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  7,  8,  9, -1, -1, -1,	  /* in0-in11     */
832*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
833*3b7f4bdeSAhmad Khalifa 	32, 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
834*3b7f4bdeSAhmad Khalifa 	16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
835*3b7f4bdeSAhmad Khalifa 	48, -1,						  /* intr0-intr1  */
836c3963bc0SZev Weiss };
837c3963bc0SZev Weiss 
838*3b7f4bdeSAhmad Khalifa static const s8 NCT6116_BEEP_BITS[NUM_BEEP_BITS] = {
839*3b7f4bdeSAhmad Khalifa 	 0,  1,  2,  3,  4,  5,  7,  8,  9, 10, 11, 12,	  /* in0-in11     */
840*3b7f4bdeSAhmad Khalifa 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
841*3b7f4bdeSAhmad Khalifa 	24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
842*3b7f4bdeSAhmad Khalifa 	16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
843*3b7f4bdeSAhmad Khalifa 	34, -1, 32					  /* intr0-intr1, beep_en */
844c3963bc0SZev Weiss };
845c3963bc0SZev Weiss 
846c3963bc0SZev Weiss static const u16 NCT6116_REG_TSI_TEMP[] = { 0x59, 0x5b };
847c3963bc0SZev Weiss 
848c3963bc0SZev Weiss static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
849c3963bc0SZev Weiss {
850c3963bc0SZev Weiss 	if (mode == 0 && pwm == 255)
851c3963bc0SZev Weiss 		return off;
852c3963bc0SZev Weiss 	return mode + 1;
853c3963bc0SZev Weiss }
854c3963bc0SZev Weiss 
855c3963bc0SZev Weiss static int pwm_enable_to_reg(enum pwm_enable mode)
856c3963bc0SZev Weiss {
857c3963bc0SZev Weiss 	if (mode == off)
858c3963bc0SZev Weiss 		return 0;
859c3963bc0SZev Weiss 	return mode - 1;
860c3963bc0SZev Weiss }
861c3963bc0SZev Weiss 
862c3963bc0SZev Weiss /*
863c3963bc0SZev Weiss  * Conversions
864c3963bc0SZev Weiss  */
865c3963bc0SZev Weiss 
866c3963bc0SZev Weiss /* 1 is DC mode, output in ms */
867c3963bc0SZev Weiss static unsigned int step_time_from_reg(u8 reg, u8 mode)
868c3963bc0SZev Weiss {
869c3963bc0SZev Weiss 	return mode ? 400 * reg : 100 * reg;
870c3963bc0SZev Weiss }
871c3963bc0SZev Weiss 
872c3963bc0SZev Weiss static u8 step_time_to_reg(unsigned int msec, u8 mode)
873c3963bc0SZev Weiss {
874c3963bc0SZev Weiss 	return clamp_val((mode ? (msec + 200) / 400 :
875c3963bc0SZev Weiss 					(msec + 50) / 100), 1, 255);
876c3963bc0SZev Weiss }
877c3963bc0SZev Weiss 
878c3963bc0SZev Weiss static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
879c3963bc0SZev Weiss {
880c3963bc0SZev Weiss 	if (reg == 0 || reg == 255)
881c3963bc0SZev Weiss 		return 0;
882c3963bc0SZev Weiss 	return 1350000U / (reg << divreg);
883c3963bc0SZev Weiss }
884c3963bc0SZev Weiss 
885c3963bc0SZev Weiss static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
886c3963bc0SZev Weiss {
887c3963bc0SZev Weiss 	if ((reg & 0xff1f) == 0xff1f)
888c3963bc0SZev Weiss 		return 0;
889c3963bc0SZev Weiss 
890c3963bc0SZev Weiss 	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
891c3963bc0SZev Weiss 
892c3963bc0SZev Weiss 	if (reg == 0)
893c3963bc0SZev Weiss 		return 0;
894c3963bc0SZev Weiss 
895c3963bc0SZev Weiss 	return 1350000U / reg;
896c3963bc0SZev Weiss }
897c3963bc0SZev Weiss 
898c3963bc0SZev Weiss static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
899c3963bc0SZev Weiss {
900c3963bc0SZev Weiss 	if (reg == 0 || reg == 0xffff)
901c3963bc0SZev Weiss 		return 0;
902c3963bc0SZev Weiss 
903c3963bc0SZev Weiss 	/*
904c3963bc0SZev Weiss 	 * Even though the registers are 16 bit wide, the fan divisor
905c3963bc0SZev Weiss 	 * still applies.
906c3963bc0SZev Weiss 	 */
907c3963bc0SZev Weiss 	return 1350000U / (reg << divreg);
908c3963bc0SZev Weiss }
909c3963bc0SZev Weiss 
910c3963bc0SZev Weiss static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg)
911c3963bc0SZev Weiss {
912c3963bc0SZev Weiss 	return reg;
913c3963bc0SZev Weiss }
914c3963bc0SZev Weiss 
915c3963bc0SZev Weiss static u16 fan_to_reg(u32 fan, unsigned int divreg)
916c3963bc0SZev Weiss {
917c3963bc0SZev Weiss 	if (!fan)
918c3963bc0SZev Weiss 		return 0;
919c3963bc0SZev Weiss 
920c3963bc0SZev Weiss 	return (1350000U / fan) >> divreg;
921c3963bc0SZev Weiss }
922c3963bc0SZev Weiss 
923c3963bc0SZev Weiss static inline unsigned int
924c3963bc0SZev Weiss div_from_reg(u8 reg)
925c3963bc0SZev Weiss {
926c3963bc0SZev Weiss 	return BIT(reg);
927c3963bc0SZev Weiss }
928c3963bc0SZev Weiss 
929c3963bc0SZev Weiss /*
930c3963bc0SZev Weiss  * Some of the voltage inputs have internal scaling, the tables below
931c3963bc0SZev Weiss  * contain 8 (the ADC LSB in mV) * scaling factor * 100
932c3963bc0SZev Weiss  */
933c3963bc0SZev Weiss static const u16 scale_in[15] = {
934c3963bc0SZev Weiss 	800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
935c3963bc0SZev Weiss 	800, 800
936c3963bc0SZev Weiss };
937c3963bc0SZev Weiss 
93813558a2eSAhmad Khalifa /*
93913558a2eSAhmad Khalifa  * NCT6798 scaling:
94013558a2eSAhmad Khalifa  *    CPUVC, IN1, AVSB, 3VCC, IN0, IN8, IN4, 3VSB, VBAT,  VTT,  IN5,  IN6, IN2,
94113558a2eSAhmad Khalifa  *      IN3, IN7
94213558a2eSAhmad Khalifa  * Additional scales to be added later: IN9 (800), VHIF (1600)
94313558a2eSAhmad Khalifa  */
94413558a2eSAhmad Khalifa static const u16 scale_in_6798[15] = {
94513558a2eSAhmad Khalifa 	800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 1600, 1600, 1600, 800,
94613558a2eSAhmad Khalifa 	800, 800
94713558a2eSAhmad Khalifa };
94813558a2eSAhmad Khalifa 
94913558a2eSAhmad Khalifa static inline long in_from_reg(u8 reg, u8 nr, const u16 *scales)
950c3963bc0SZev Weiss {
95113558a2eSAhmad Khalifa 	return DIV_ROUND_CLOSEST(reg * scales[nr], 100);
952c3963bc0SZev Weiss }
953c3963bc0SZev Weiss 
95413558a2eSAhmad Khalifa static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scales)
955c3963bc0SZev Weiss {
95613558a2eSAhmad Khalifa 	return clamp_val(DIV_ROUND_CLOSEST(val * 100, scales[nr]), 0, 255);
957c3963bc0SZev Weiss }
958c3963bc0SZev Weiss 
959c3963bc0SZev Weiss /* TSI temperatures are in 8.3 format */
960c3963bc0SZev Weiss static inline unsigned int tsi_temp_from_reg(unsigned int reg)
961c3963bc0SZev Weiss {
962c3963bc0SZev Weiss 	return (reg >> 5) * 125;
963c3963bc0SZev Weiss }
964c3963bc0SZev Weiss 
965c3963bc0SZev Weiss /*
966c3963bc0SZev Weiss  * Data structures and manipulation thereof
967c3963bc0SZev Weiss  */
968c3963bc0SZev Weiss 
969c3963bc0SZev Weiss struct sensor_device_template {
970c3963bc0SZev Weiss 	struct device_attribute dev_attr;
971c3963bc0SZev Weiss 	union {
972c3963bc0SZev Weiss 		struct {
973c3963bc0SZev Weiss 			u8 nr;
974c3963bc0SZev Weiss 			u8 index;
975c3963bc0SZev Weiss 		} s;
976c3963bc0SZev Weiss 		int index;
977c3963bc0SZev Weiss 	} u;
978c3963bc0SZev Weiss 	bool s2;	/* true if both index and nr are used */
979c3963bc0SZev Weiss };
980c3963bc0SZev Weiss 
981c3963bc0SZev Weiss struct sensor_device_attr_u {
982c3963bc0SZev Weiss 	union {
983c3963bc0SZev Weiss 		struct sensor_device_attribute a1;
984c3963bc0SZev Weiss 		struct sensor_device_attribute_2 a2;
985c3963bc0SZev Weiss 	} u;
986c3963bc0SZev Weiss 	char name[32];
987c3963bc0SZev Weiss };
988c3963bc0SZev Weiss 
989c3963bc0SZev Weiss #define __TEMPLATE_ATTR(_template, _mode, _show, _store) {	\
990c3963bc0SZev Weiss 	.attr = {.name = _template, .mode = _mode },		\
991c3963bc0SZev Weiss 	.show	= _show,					\
992c3963bc0SZev Weiss 	.store	= _store,					\
993c3963bc0SZev Weiss }
994c3963bc0SZev Weiss 
995c3963bc0SZev Weiss #define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index)	\
996c3963bc0SZev Weiss 	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
997c3963bc0SZev Weiss 	  .u.index = _index,						\
998c3963bc0SZev Weiss 	  .s2 = false }
999c3963bc0SZev Weiss 
1000c3963bc0SZev Weiss #define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
1001c3963bc0SZev Weiss 				 _nr, _index)				\
1002c3963bc0SZev Weiss 	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
1003c3963bc0SZev Weiss 	  .u.s.index = _index,						\
1004c3963bc0SZev Weiss 	  .u.s.nr = _nr,						\
1005c3963bc0SZev Weiss 	  .s2 = true }
1006c3963bc0SZev Weiss 
1007c3963bc0SZev Weiss #define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index)	\
1008c3963bc0SZev Weiss static struct sensor_device_template sensor_dev_template_##_name	\
1009c3963bc0SZev Weiss 	= SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store,	\
1010c3963bc0SZev Weiss 				 _index)
1011c3963bc0SZev Weiss 
1012c3963bc0SZev Weiss #define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store,	\
1013c3963bc0SZev Weiss 			  _nr, _index)					\
1014c3963bc0SZev Weiss static struct sensor_device_template sensor_dev_template_##_name	\
1015c3963bc0SZev Weiss 	= SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
1016c3963bc0SZev Weiss 				 _nr, _index)
1017c3963bc0SZev Weiss 
1018c3963bc0SZev Weiss struct sensor_template_group {
1019c3963bc0SZev Weiss 	struct sensor_device_template **templates;
1020c3963bc0SZev Weiss 	umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1021c3963bc0SZev Weiss 	int base;
1022c3963bc0SZev Weiss };
1023c3963bc0SZev Weiss 
1024c3963bc0SZev Weiss static int nct6775_add_template_attr_group(struct device *dev, struct nct6775_data *data,
1025c3963bc0SZev Weiss 					   const struct sensor_template_group *tg, int repeat)
1026c3963bc0SZev Weiss {
1027c3963bc0SZev Weiss 	struct attribute_group *group;
1028c3963bc0SZev Weiss 	struct sensor_device_attr_u *su;
1029c3963bc0SZev Weiss 	struct sensor_device_attribute *a;
1030c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *a2;
1031c3963bc0SZev Weiss 	struct attribute **attrs;
1032c3963bc0SZev Weiss 	struct sensor_device_template **t;
1033c3963bc0SZev Weiss 	int i, count;
1034c3963bc0SZev Weiss 
1035c3963bc0SZev Weiss 	if (repeat <= 0)
1036c3963bc0SZev Weiss 		return -EINVAL;
1037c3963bc0SZev Weiss 
1038c3963bc0SZev Weiss 	t = tg->templates;
1039c3963bc0SZev Weiss 	for (count = 0; *t; t++, count++)
1040c3963bc0SZev Weiss 		;
1041c3963bc0SZev Weiss 
1042c3963bc0SZev Weiss 	if (count == 0)
1043c3963bc0SZev Weiss 		return -EINVAL;
1044c3963bc0SZev Weiss 
1045c3963bc0SZev Weiss 	group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1046c3963bc0SZev Weiss 	if (group == NULL)
1047c3963bc0SZev Weiss 		return -ENOMEM;
1048c3963bc0SZev Weiss 
1049c3963bc0SZev Weiss 	attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
1050c3963bc0SZev Weiss 			     GFP_KERNEL);
1051c3963bc0SZev Weiss 	if (attrs == NULL)
1052c3963bc0SZev Weiss 		return -ENOMEM;
1053c3963bc0SZev Weiss 
1054c3963bc0SZev Weiss 	su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
1055c3963bc0SZev Weiss 			       GFP_KERNEL);
1056c3963bc0SZev Weiss 	if (su == NULL)
1057c3963bc0SZev Weiss 		return -ENOMEM;
1058c3963bc0SZev Weiss 
1059c3963bc0SZev Weiss 	group->attrs = attrs;
1060c3963bc0SZev Weiss 	group->is_visible = tg->is_visible;
1061c3963bc0SZev Weiss 
1062c3963bc0SZev Weiss 	for (i = 0; i < repeat; i++) {
1063c3963bc0SZev Weiss 		t = tg->templates;
1064c3963bc0SZev Weiss 		while (*t != NULL) {
1065c3963bc0SZev Weiss 			snprintf(su->name, sizeof(su->name),
1066c3963bc0SZev Weiss 				 (*t)->dev_attr.attr.name, tg->base + i);
1067c3963bc0SZev Weiss 			if ((*t)->s2) {
1068c3963bc0SZev Weiss 				a2 = &su->u.a2;
1069c3963bc0SZev Weiss 				sysfs_attr_init(&a2->dev_attr.attr);
1070c3963bc0SZev Weiss 				a2->dev_attr.attr.name = su->name;
1071c3963bc0SZev Weiss 				a2->nr = (*t)->u.s.nr + i;
1072c3963bc0SZev Weiss 				a2->index = (*t)->u.s.index;
1073c3963bc0SZev Weiss 				a2->dev_attr.attr.mode =
1074c3963bc0SZev Weiss 				  (*t)->dev_attr.attr.mode;
1075c3963bc0SZev Weiss 				a2->dev_attr.show = (*t)->dev_attr.show;
1076c3963bc0SZev Weiss 				a2->dev_attr.store = (*t)->dev_attr.store;
1077c3963bc0SZev Weiss 				*attrs = &a2->dev_attr.attr;
1078c3963bc0SZev Weiss 			} else {
1079c3963bc0SZev Weiss 				a = &su->u.a1;
1080c3963bc0SZev Weiss 				sysfs_attr_init(&a->dev_attr.attr);
1081c3963bc0SZev Weiss 				a->dev_attr.attr.name = su->name;
1082c3963bc0SZev Weiss 				a->index = (*t)->u.index + i;
1083c3963bc0SZev Weiss 				a->dev_attr.attr.mode =
1084c3963bc0SZev Weiss 				  (*t)->dev_attr.attr.mode;
1085c3963bc0SZev Weiss 				a->dev_attr.show = (*t)->dev_attr.show;
1086c3963bc0SZev Weiss 				a->dev_attr.store = (*t)->dev_attr.store;
1087c3963bc0SZev Weiss 				*attrs = &a->dev_attr.attr;
1088c3963bc0SZev Weiss 			}
1089c3963bc0SZev Weiss 			attrs++;
1090c3963bc0SZev Weiss 			su++;
1091c3963bc0SZev Weiss 			t++;
1092c3963bc0SZev Weiss 		}
1093c3963bc0SZev Weiss 	}
1094c3963bc0SZev Weiss 
1095c3963bc0SZev Weiss 	return nct6775_add_attr_group(data, group);
1096c3963bc0SZev Weiss }
1097c3963bc0SZev Weiss 
1098c3963bc0SZev Weiss bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg)
1099c3963bc0SZev Weiss {
1100c3963bc0SZev Weiss 	switch (data->kind) {
1101c3963bc0SZev Weiss 	case nct6106:
1102c3963bc0SZev Weiss 		return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1103c3963bc0SZev Weiss 		  (reg >= 0x59 && reg < 0x69 && (reg & 1)) ||
1104c3963bc0SZev Weiss 		  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1105c3963bc0SZev Weiss 		  reg == 0x111 || reg == 0x121 || reg == 0x131;
1106c3963bc0SZev Weiss 	case nct6116:
1107c3963bc0SZev Weiss 		return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1108c3963bc0SZev Weiss 		  reg == 0x26 || reg == 0x28 || reg == 0x59 || reg == 0x5b ||
1109c3963bc0SZev Weiss 		  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 || reg == 0xe6 ||
1110c3963bc0SZev Weiss 		  reg == 0xe8 || reg == 0x111 || reg == 0x121 || reg == 0x131 ||
1111c3963bc0SZev Weiss 		  reg == 0x191 || reg == 0x1a1;
1112c3963bc0SZev Weiss 	case nct6775:
1113c3963bc0SZev Weiss 		return (((reg & 0xff00) == 0x100 ||
1114c3963bc0SZev Weiss 		    (reg & 0xff00) == 0x200) &&
1115c3963bc0SZev Weiss 		   ((reg & 0x00ff) == 0x50 ||
1116c3963bc0SZev Weiss 		    (reg & 0x00ff) == 0x53 ||
1117c3963bc0SZev Weiss 		    (reg & 0x00ff) == 0x55)) ||
1118c3963bc0SZev Weiss 		  (reg & 0xfff0) == 0x630 ||
1119c3963bc0SZev Weiss 		  reg == 0x640 || reg == 0x642 ||
1120c3963bc0SZev Weiss 		  reg == 0x662 || reg == 0x669 ||
1121c3963bc0SZev Weiss 		  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1122c3963bc0SZev Weiss 		  reg == 0x73 || reg == 0x75 || reg == 0x77;
1123c3963bc0SZev Weiss 	case nct6776:
1124c3963bc0SZev Weiss 		return (((reg & 0xff00) == 0x100 ||
1125c3963bc0SZev Weiss 		    (reg & 0xff00) == 0x200) &&
1126c3963bc0SZev Weiss 		   ((reg & 0x00ff) == 0x50 ||
1127c3963bc0SZev Weiss 		    (reg & 0x00ff) == 0x53 ||
1128c3963bc0SZev Weiss 		    (reg & 0x00ff) == 0x55)) ||
1129c3963bc0SZev Weiss 		  (reg & 0xfff0) == 0x630 ||
1130c3963bc0SZev Weiss 		  reg == 0x402 ||
1131c3963bc0SZev Weiss 		  (reg >= 0x409 && reg < 0x419 && (reg & 1)) ||
1132c3963bc0SZev Weiss 		  reg == 0x640 || reg == 0x642 ||
1133c3963bc0SZev Weiss 		  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1134c3963bc0SZev Weiss 		  reg == 0x73 || reg == 0x75 || reg == 0x77;
1135c3963bc0SZev Weiss 	case nct6779:
1136c3963bc0SZev Weiss 	case nct6791:
1137c3963bc0SZev Weiss 	case nct6792:
1138c3963bc0SZev Weiss 	case nct6793:
1139c3963bc0SZev Weiss 	case nct6795:
1140c3963bc0SZev Weiss 	case nct6796:
1141c3963bc0SZev Weiss 	case nct6797:
1142c3963bc0SZev Weiss 	case nct6798:
1143aee395bbSGuenter Roeck 	case nct6799:
1144c3963bc0SZev Weiss 		return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
1145c3963bc0SZev Weiss 		  (reg & 0xfff0) == 0x4c0 ||
1146c3963bc0SZev Weiss 		  reg == 0x402 ||
1147c3963bc0SZev Weiss 		  (reg >= 0x409 && reg < 0x419 && (reg & 1)) ||
1148c3963bc0SZev Weiss 		  reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1149c3963bc0SZev Weiss 		  reg == 0x640 || reg == 0x642 || reg == 0x64a ||
1150c3963bc0SZev Weiss 		  reg == 0x64c ||
1151c3963bc0SZev Weiss 		  reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
1152c3963bc0SZev Weiss 		  reg == 0x7b || reg == 0x7d;
1153c3963bc0SZev Weiss 	}
1154c3963bc0SZev Weiss 	return false;
1155c3963bc0SZev Weiss }
1156c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_reg_is_word_sized);
1157c3963bc0SZev Weiss 
1158c3963bc0SZev Weiss /* We left-align 8-bit temperature values to make the code simpler */
1159c3963bc0SZev Weiss static int nct6775_read_temp(struct nct6775_data *data, u16 reg, u16 *val)
1160c3963bc0SZev Weiss {
1161c3963bc0SZev Weiss 	int err;
1162c3963bc0SZev Weiss 
1163c3963bc0SZev Weiss 	err = nct6775_read_value(data, reg, val);
1164c3963bc0SZev Weiss 	if (err)
1165c3963bc0SZev Weiss 		return err;
1166c3963bc0SZev Weiss 
1167c3963bc0SZev Weiss 	if (!nct6775_reg_is_word_sized(data, reg))
1168c3963bc0SZev Weiss 		*val <<= 8;
1169c3963bc0SZev Weiss 
1170c3963bc0SZev Weiss 	return 0;
1171c3963bc0SZev Weiss }
1172c3963bc0SZev Weiss 
1173c3963bc0SZev Weiss /* This function assumes that the caller holds data->update_lock */
1174c3963bc0SZev Weiss static int nct6775_write_fan_div(struct nct6775_data *data, int nr)
1175c3963bc0SZev Weiss {
1176c3963bc0SZev Weiss 	u16 reg;
1177c3963bc0SZev Weiss 	int err;
1178c3963bc0SZev Weiss 	u16 fandiv_reg = nr < 2 ? NCT6775_REG_FANDIV1 : NCT6775_REG_FANDIV2;
1179c3963bc0SZev Weiss 	unsigned int oddshift = (nr & 1) * 4; /* masks shift by four if nr is odd */
1180c3963bc0SZev Weiss 
1181c3963bc0SZev Weiss 	err = nct6775_read_value(data, fandiv_reg, &reg);
1182c3963bc0SZev Weiss 	if (err)
1183c3963bc0SZev Weiss 		return err;
1184c3963bc0SZev Weiss 	reg &= 0x70 >> oddshift;
11852fbb848bSZev Weiss 	reg |= (data->fan_div[nr] & 0x7) << oddshift;
1186c3963bc0SZev Weiss 	return nct6775_write_value(data, fandiv_reg, reg);
1187c3963bc0SZev Weiss }
1188c3963bc0SZev Weiss 
1189c3963bc0SZev Weiss static int nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1190c3963bc0SZev Weiss {
1191c3963bc0SZev Weiss 	if (data->kind == nct6775)
1192c3963bc0SZev Weiss 		return nct6775_write_fan_div(data, nr);
1193c3963bc0SZev Weiss 	return 0;
1194c3963bc0SZev Weiss }
1195c3963bc0SZev Weiss 
1196c3963bc0SZev Weiss static int nct6775_update_fan_div(struct nct6775_data *data)
1197c3963bc0SZev Weiss {
1198c3963bc0SZev Weiss 	int err;
1199c3963bc0SZev Weiss 	u16 i;
1200c3963bc0SZev Weiss 
1201c3963bc0SZev Weiss 	err = nct6775_read_value(data, NCT6775_REG_FANDIV1, &i);
1202c3963bc0SZev Weiss 	if (err)
1203c3963bc0SZev Weiss 		return err;
1204c3963bc0SZev Weiss 	data->fan_div[0] = i & 0x7;
1205c3963bc0SZev Weiss 	data->fan_div[1] = (i & 0x70) >> 4;
1206c3963bc0SZev Weiss 	err = nct6775_read_value(data, NCT6775_REG_FANDIV2, &i);
1207c3963bc0SZev Weiss 	if (err)
1208c3963bc0SZev Weiss 		return err;
1209c3963bc0SZev Weiss 	data->fan_div[2] = i & 0x7;
1210c3963bc0SZev Weiss 	if (data->has_fan & BIT(3))
1211c3963bc0SZev Weiss 		data->fan_div[3] = (i & 0x70) >> 4;
1212c3963bc0SZev Weiss 
1213c3963bc0SZev Weiss 	return 0;
1214c3963bc0SZev Weiss }
1215c3963bc0SZev Weiss 
1216c3963bc0SZev Weiss static int nct6775_update_fan_div_common(struct nct6775_data *data)
1217c3963bc0SZev Weiss {
1218c3963bc0SZev Weiss 	if (data->kind == nct6775)
1219c3963bc0SZev Weiss 		return nct6775_update_fan_div(data);
1220c3963bc0SZev Weiss 	return 0;
1221c3963bc0SZev Weiss }
1222c3963bc0SZev Weiss 
1223c3963bc0SZev Weiss static int nct6775_init_fan_div(struct nct6775_data *data)
1224c3963bc0SZev Weiss {
1225c3963bc0SZev Weiss 	int i, err;
1226c3963bc0SZev Weiss 
1227c3963bc0SZev Weiss 	err = nct6775_update_fan_div_common(data);
1228c3963bc0SZev Weiss 	if (err)
1229c3963bc0SZev Weiss 		return err;
1230c3963bc0SZev Weiss 
1231c3963bc0SZev Weiss 	/*
1232c3963bc0SZev Weiss 	 * For all fans, start with highest divider value if the divider
1233c3963bc0SZev Weiss 	 * register is not initialized. This ensures that we get a
1234c3963bc0SZev Weiss 	 * reading from the fan count register, even if it is not optimal.
1235c3963bc0SZev Weiss 	 * We'll compute a better divider later on.
1236c3963bc0SZev Weiss 	 */
1237c3963bc0SZev Weiss 	for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
1238c3963bc0SZev Weiss 		if (!(data->has_fan & BIT(i)))
1239c3963bc0SZev Weiss 			continue;
1240c3963bc0SZev Weiss 		if (data->fan_div[i] == 0) {
1241c3963bc0SZev Weiss 			data->fan_div[i] = 7;
1242c3963bc0SZev Weiss 			err = nct6775_write_fan_div_common(data, i);
1243c3963bc0SZev Weiss 			if (err)
1244c3963bc0SZev Weiss 				return err;
1245c3963bc0SZev Weiss 		}
1246c3963bc0SZev Weiss 	}
1247c3963bc0SZev Weiss 
1248c3963bc0SZev Weiss 	return 0;
1249c3963bc0SZev Weiss }
1250c3963bc0SZev Weiss 
1251c3963bc0SZev Weiss static int nct6775_init_fan_common(struct device *dev,
1252c3963bc0SZev Weiss 				   struct nct6775_data *data)
1253c3963bc0SZev Weiss {
1254c3963bc0SZev Weiss 	int i, err;
1255c3963bc0SZev Weiss 	u16 reg;
1256c3963bc0SZev Weiss 
1257c3963bc0SZev Weiss 	if (data->has_fan_div) {
1258c3963bc0SZev Weiss 		err = nct6775_init_fan_div(data);
1259c3963bc0SZev Weiss 		if (err)
1260c3963bc0SZev Weiss 			return err;
1261c3963bc0SZev Weiss 	}
1262c3963bc0SZev Weiss 
1263c3963bc0SZev Weiss 	/*
1264c3963bc0SZev Weiss 	 * If fan_min is not set (0), set it to 0xff to disable it. This
1265c3963bc0SZev Weiss 	 * prevents the unnecessary warning when fanX_min is reported as 0.
1266c3963bc0SZev Weiss 	 */
1267c3963bc0SZev Weiss 	for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
1268c3963bc0SZev Weiss 		if (data->has_fan_min & BIT(i)) {
1269c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_FAN_MIN[i], &reg);
1270c3963bc0SZev Weiss 			if (err)
1271c3963bc0SZev Weiss 				return err;
1272c3963bc0SZev Weiss 			if (!reg) {
1273c3963bc0SZev Weiss 				err = nct6775_write_value(data, data->REG_FAN_MIN[i],
1274c3963bc0SZev Weiss 							  data->has_fan_div ? 0xff : 0xff1f);
1275c3963bc0SZev Weiss 				if (err)
1276c3963bc0SZev Weiss 					return err;
1277c3963bc0SZev Weiss 			}
1278c3963bc0SZev Weiss 		}
1279c3963bc0SZev Weiss 	}
1280c3963bc0SZev Weiss 
1281c3963bc0SZev Weiss 	return 0;
1282c3963bc0SZev Weiss }
1283c3963bc0SZev Weiss 
1284c3963bc0SZev Weiss static int nct6775_select_fan_div(struct device *dev,
1285c3963bc0SZev Weiss 				  struct nct6775_data *data, int nr, u16 reg)
1286c3963bc0SZev Weiss {
1287c3963bc0SZev Weiss 	int err;
1288c3963bc0SZev Weiss 	u8 fan_div = data->fan_div[nr];
1289c3963bc0SZev Weiss 	u16 fan_min;
1290c3963bc0SZev Weiss 
1291c3963bc0SZev Weiss 	if (!data->has_fan_div)
1292c3963bc0SZev Weiss 		return 0;
1293c3963bc0SZev Weiss 
1294c3963bc0SZev Weiss 	/*
1295c3963bc0SZev Weiss 	 * If we failed to measure the fan speed, or the reported value is not
1296c3963bc0SZev Weiss 	 * in the optimal range, and the clock divider can be modified,
1297c3963bc0SZev Weiss 	 * let's try that for next time.
1298c3963bc0SZev Weiss 	 */
1299c3963bc0SZev Weiss 	if (reg == 0x00 && fan_div < 0x07)
1300c3963bc0SZev Weiss 		fan_div++;
1301c3963bc0SZev Weiss 	else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1302c3963bc0SZev Weiss 		fan_div--;
1303c3963bc0SZev Weiss 
1304c3963bc0SZev Weiss 	if (fan_div != data->fan_div[nr]) {
1305c3963bc0SZev Weiss 		dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1306c3963bc0SZev Weiss 			nr + 1, div_from_reg(data->fan_div[nr]),
1307c3963bc0SZev Weiss 			div_from_reg(fan_div));
1308c3963bc0SZev Weiss 
1309c3963bc0SZev Weiss 		/* Preserve min limit if possible */
1310c3963bc0SZev Weiss 		if (data->has_fan_min & BIT(nr)) {
1311c3963bc0SZev Weiss 			fan_min = data->fan_min[nr];
1312c3963bc0SZev Weiss 			if (fan_div > data->fan_div[nr]) {
1313c3963bc0SZev Weiss 				if (fan_min != 255 && fan_min > 1)
1314c3963bc0SZev Weiss 					fan_min >>= 1;
1315c3963bc0SZev Weiss 			} else {
1316c3963bc0SZev Weiss 				if (fan_min != 255) {
1317c3963bc0SZev Weiss 					fan_min <<= 1;
1318c3963bc0SZev Weiss 					if (fan_min > 254)
1319c3963bc0SZev Weiss 						fan_min = 254;
1320c3963bc0SZev Weiss 				}
1321c3963bc0SZev Weiss 			}
1322c3963bc0SZev Weiss 			if (fan_min != data->fan_min[nr]) {
1323c3963bc0SZev Weiss 				data->fan_min[nr] = fan_min;
1324c3963bc0SZev Weiss 				err = nct6775_write_value(data, data->REG_FAN_MIN[nr], fan_min);
1325c3963bc0SZev Weiss 				if (err)
1326c3963bc0SZev Weiss 					return err;
1327c3963bc0SZev Weiss 			}
1328c3963bc0SZev Weiss 		}
1329c3963bc0SZev Weiss 		data->fan_div[nr] = fan_div;
1330c3963bc0SZev Weiss 		err = nct6775_write_fan_div_common(data, nr);
1331c3963bc0SZev Weiss 		if (err)
1332c3963bc0SZev Weiss 			return err;
1333c3963bc0SZev Weiss 	}
1334c3963bc0SZev Weiss 
1335c3963bc0SZev Weiss 	return 0;
1336c3963bc0SZev Weiss }
1337c3963bc0SZev Weiss 
1338c3963bc0SZev Weiss static int nct6775_update_pwm(struct device *dev)
1339c3963bc0SZev Weiss {
1340c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1341c3963bc0SZev Weiss 	int i, j, err;
1342c3963bc0SZev Weiss 	u16 fanmodecfg, reg;
1343c3963bc0SZev Weiss 	bool duty_is_dc;
1344c3963bc0SZev Weiss 
1345c3963bc0SZev Weiss 	for (i = 0; i < data->pwm_num; i++) {
1346c3963bc0SZev Weiss 		if (!(data->has_pwm & BIT(i)))
1347c3963bc0SZev Weiss 			continue;
1348c3963bc0SZev Weiss 
1349c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_PWM_MODE[i], &reg);
1350c3963bc0SZev Weiss 		if (err)
1351c3963bc0SZev Weiss 			return err;
1352c3963bc0SZev Weiss 		duty_is_dc = data->REG_PWM_MODE[i] && (reg & data->PWM_MODE_MASK[i]);
1353c3963bc0SZev Weiss 		data->pwm_mode[i] = !duty_is_dc;
1354c3963bc0SZev Weiss 
1355c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_FAN_MODE[i], &fanmodecfg);
1356c3963bc0SZev Weiss 		if (err)
1357c3963bc0SZev Weiss 			return err;
1358c3963bc0SZev Weiss 		for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1359c3963bc0SZev Weiss 			if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1360c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_PWM[j][i], &reg);
1361c3963bc0SZev Weiss 				if (err)
1362c3963bc0SZev Weiss 					return err;
1363c3963bc0SZev Weiss 				data->pwm[j][i] = reg;
1364c3963bc0SZev Weiss 			}
1365c3963bc0SZev Weiss 		}
1366c3963bc0SZev Weiss 
1367c3963bc0SZev Weiss 		data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1368c3963bc0SZev Weiss 							(fanmodecfg >> 4) & 7);
1369c3963bc0SZev Weiss 
1370c3963bc0SZev Weiss 		if (!data->temp_tolerance[0][i] ||
1371c3963bc0SZev Weiss 		    data->pwm_enable[i] != speed_cruise)
1372c3963bc0SZev Weiss 			data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1373c3963bc0SZev Weiss 		if (!data->target_speed_tolerance[i] ||
1374c3963bc0SZev Weiss 		    data->pwm_enable[i] == speed_cruise) {
1375c3963bc0SZev Weiss 			u8 t = fanmodecfg & 0x0f;
1376c3963bc0SZev Weiss 
1377c3963bc0SZev Weiss 			if (data->REG_TOLERANCE_H) {
1378c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_TOLERANCE_H[i], &reg);
1379c3963bc0SZev Weiss 				if (err)
1380c3963bc0SZev Weiss 					return err;
1381c3963bc0SZev Weiss 				t |= (reg & 0x70) >> 1;
1382c3963bc0SZev Weiss 			}
1383c3963bc0SZev Weiss 			data->target_speed_tolerance[i] = t;
1384c3963bc0SZev Weiss 		}
1385c3963bc0SZev Weiss 
1386c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_CRITICAL_TEMP_TOLERANCE[i], &reg);
1387c3963bc0SZev Weiss 		if (err)
1388c3963bc0SZev Weiss 			return err;
1389c3963bc0SZev Weiss 		data->temp_tolerance[1][i] = reg;
1390c3963bc0SZev Weiss 
1391c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SEL[i], &reg);
1392c3963bc0SZev Weiss 		if (err)
1393c3963bc0SZev Weiss 			return err;
1394c3963bc0SZev Weiss 		data->pwm_temp_sel[i] = reg & 0x1f;
1395c3963bc0SZev Weiss 		/* If fan can stop, report floor as 0 */
1396c3963bc0SZev Weiss 		if (reg & 0x80)
1397c3963bc0SZev Weiss 			data->pwm[2][i] = 0;
1398c3963bc0SZev Weiss 
1399c3963bc0SZev Weiss 		if (!data->REG_WEIGHT_TEMP_SEL[i])
1400c3963bc0SZev Weiss 			continue;
1401c3963bc0SZev Weiss 
1402c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i], &reg);
1403c3963bc0SZev Weiss 		if (err)
1404c3963bc0SZev Weiss 			return err;
1405c3963bc0SZev Weiss 		data->pwm_weight_temp_sel[i] = reg & 0x1f;
1406c3963bc0SZev Weiss 		/* If weight is disabled, report weight source as 0 */
1407c3963bc0SZev Weiss 		if (!(reg & 0x80))
1408c3963bc0SZev Weiss 			data->pwm_weight_temp_sel[i] = 0;
1409c3963bc0SZev Weiss 
1410c3963bc0SZev Weiss 		/* Weight temp data */
1411c3963bc0SZev Weiss 		for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
1412c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_WEIGHT_TEMP[j][i], &reg);
1413c3963bc0SZev Weiss 			if (err)
1414c3963bc0SZev Weiss 				return err;
1415c3963bc0SZev Weiss 			data->weight_temp[j][i] = reg;
1416c3963bc0SZev Weiss 		}
1417c3963bc0SZev Weiss 	}
1418c3963bc0SZev Weiss 
1419c3963bc0SZev Weiss 	return 0;
1420c3963bc0SZev Weiss }
1421c3963bc0SZev Weiss 
1422c3963bc0SZev Weiss static int nct6775_update_pwm_limits(struct device *dev)
1423c3963bc0SZev Weiss {
1424c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1425c3963bc0SZev Weiss 	int i, j, err;
1426c3963bc0SZev Weiss 	u16 reg, reg_t;
1427c3963bc0SZev Weiss 
1428c3963bc0SZev Weiss 	for (i = 0; i < data->pwm_num; i++) {
1429c3963bc0SZev Weiss 		if (!(data->has_pwm & BIT(i)))
1430c3963bc0SZev Weiss 			continue;
1431c3963bc0SZev Weiss 
1432c3963bc0SZev Weiss 		for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
1433c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_FAN_TIME[j][i], &reg);
1434c3963bc0SZev Weiss 			if (err)
1435c3963bc0SZev Weiss 				return err;
1436c3963bc0SZev Weiss 			data->fan_time[j][i] = reg;
1437c3963bc0SZev Weiss 		}
1438c3963bc0SZev Weiss 
1439c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TARGET[i], &reg_t);
1440c3963bc0SZev Weiss 		if (err)
1441c3963bc0SZev Weiss 			return err;
1442c3963bc0SZev Weiss 
1443c3963bc0SZev Weiss 		/* Update only in matching mode or if never updated */
1444c3963bc0SZev Weiss 		if (!data->target_temp[i] ||
1445c3963bc0SZev Weiss 		    data->pwm_enable[i] == thermal_cruise)
1446c3963bc0SZev Weiss 			data->target_temp[i] = reg_t & data->target_temp_mask;
1447c3963bc0SZev Weiss 		if (!data->target_speed[i] ||
1448c3963bc0SZev Weiss 		    data->pwm_enable[i] == speed_cruise) {
1449c3963bc0SZev Weiss 			if (data->REG_TOLERANCE_H) {
1450c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_TOLERANCE_H[i], &reg);
1451c3963bc0SZev Weiss 				if (err)
1452c3963bc0SZev Weiss 					return err;
1453c3963bc0SZev Weiss 				reg_t |= (reg & 0x0f) << 8;
1454c3963bc0SZev Weiss 			}
1455c3963bc0SZev Weiss 			data->target_speed[i] = reg_t;
1456c3963bc0SZev Weiss 		}
1457c3963bc0SZev Weiss 
1458c3963bc0SZev Weiss 		for (j = 0; j < data->auto_pwm_num; j++) {
1459c3963bc0SZev Weiss 			err = nct6775_read_value(data, NCT6775_AUTO_PWM(data, i, j), &reg);
1460c3963bc0SZev Weiss 			if (err)
1461c3963bc0SZev Weiss 				return err;
1462c3963bc0SZev Weiss 			data->auto_pwm[i][j] = reg;
1463c3963bc0SZev Weiss 
1464c3963bc0SZev Weiss 			err = nct6775_read_value(data, NCT6775_AUTO_TEMP(data, i, j), &reg);
1465c3963bc0SZev Weiss 			if (err)
1466c3963bc0SZev Weiss 				return err;
1467c3963bc0SZev Weiss 			data->auto_temp[i][j] = reg;
1468c3963bc0SZev Weiss 		}
1469c3963bc0SZev Weiss 
1470c3963bc0SZev Weiss 		/* critical auto_pwm temperature data */
1471c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_CRITICAL_TEMP[i], &reg);
1472c3963bc0SZev Weiss 		if (err)
1473c3963bc0SZev Weiss 			return err;
1474c3963bc0SZev Weiss 		data->auto_temp[i][data->auto_pwm_num] = reg;
1475c3963bc0SZev Weiss 
1476c3963bc0SZev Weiss 		switch (data->kind) {
1477c3963bc0SZev Weiss 		case nct6775:
1478c3963bc0SZev Weiss 			err = nct6775_read_value(data, NCT6775_REG_CRITICAL_ENAB[i], &reg);
1479c3963bc0SZev Weiss 			if (err)
1480c3963bc0SZev Weiss 				return err;
1481c3963bc0SZev Weiss 			data->auto_pwm[i][data->auto_pwm_num] =
1482c3963bc0SZev Weiss 						(reg & 0x02) ? 0xff : 0x00;
1483c3963bc0SZev Weiss 			break;
1484c3963bc0SZev Weiss 		case nct6776:
1485c3963bc0SZev Weiss 			data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1486c3963bc0SZev Weiss 			break;
1487c3963bc0SZev Weiss 		case nct6106:
1488c3963bc0SZev Weiss 		case nct6116:
1489c3963bc0SZev Weiss 		case nct6779:
1490c3963bc0SZev Weiss 		case nct6791:
1491c3963bc0SZev Weiss 		case nct6792:
1492c3963bc0SZev Weiss 		case nct6793:
1493c3963bc0SZev Weiss 		case nct6795:
1494c3963bc0SZev Weiss 		case nct6796:
1495c3963bc0SZev Weiss 		case nct6797:
1496c3963bc0SZev Weiss 		case nct6798:
1497aee395bbSGuenter Roeck 		case nct6799:
1498c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i], &reg);
1499c3963bc0SZev Weiss 			if (err)
1500c3963bc0SZev Weiss 				return err;
1501c3963bc0SZev Weiss 			if (reg & data->CRITICAL_PWM_ENABLE_MASK) {
1502c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_CRITICAL_PWM[i], &reg);
1503c3963bc0SZev Weiss 				if (err)
1504c3963bc0SZev Weiss 					return err;
1505c3963bc0SZev Weiss 			} else {
1506c3963bc0SZev Weiss 				reg = 0xff;
1507c3963bc0SZev Weiss 			}
1508c3963bc0SZev Weiss 			data->auto_pwm[i][data->auto_pwm_num] = reg;
1509c3963bc0SZev Weiss 			break;
1510c3963bc0SZev Weiss 		}
1511c3963bc0SZev Weiss 	}
1512c3963bc0SZev Weiss 
1513c3963bc0SZev Weiss 	return 0;
1514c3963bc0SZev Weiss }
1515c3963bc0SZev Weiss 
1516f4e6960fSZev Weiss struct nct6775_data *nct6775_update_device(struct device *dev)
1517c3963bc0SZev Weiss {
1518c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1519c3963bc0SZev Weiss 	int i, j, err = 0;
1520c3963bc0SZev Weiss 	u16 reg;
1521c3963bc0SZev Weiss 
1522c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
1523c3963bc0SZev Weiss 
1524c3963bc0SZev Weiss 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1525c3963bc0SZev Weiss 	    || !data->valid) {
1526c3963bc0SZev Weiss 		/* Fan clock dividers */
1527c3963bc0SZev Weiss 		err = nct6775_update_fan_div_common(data);
1528c3963bc0SZev Weiss 		if (err)
1529c3963bc0SZev Weiss 			goto out;
1530c3963bc0SZev Weiss 
1531c3963bc0SZev Weiss 		/* Measured voltages and limits */
1532c3963bc0SZev Weiss 		for (i = 0; i < data->in_num; i++) {
1533c3963bc0SZev Weiss 			if (!(data->have_in & BIT(i)))
1534c3963bc0SZev Weiss 				continue;
1535c3963bc0SZev Weiss 
1536c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_VIN[i], &reg);
1537c3963bc0SZev Weiss 			if (err)
1538c3963bc0SZev Weiss 				goto out;
1539c3963bc0SZev Weiss 			data->in[i][0] = reg;
1540c3963bc0SZev Weiss 
1541c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_IN_MINMAX[0][i], &reg);
1542c3963bc0SZev Weiss 			if (err)
1543c3963bc0SZev Weiss 				goto out;
1544c3963bc0SZev Weiss 			data->in[i][1] = reg;
1545c3963bc0SZev Weiss 
1546c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_IN_MINMAX[1][i], &reg);
1547c3963bc0SZev Weiss 			if (err)
1548c3963bc0SZev Weiss 				goto out;
1549c3963bc0SZev Weiss 			data->in[i][2] = reg;
1550c3963bc0SZev Weiss 		}
1551c3963bc0SZev Weiss 
1552c3963bc0SZev Weiss 		/* Measured fan speeds and limits */
1553c3963bc0SZev Weiss 		for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
1554c3963bc0SZev Weiss 			if (!(data->has_fan & BIT(i)))
1555c3963bc0SZev Weiss 				continue;
1556c3963bc0SZev Weiss 
1557c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_FAN[i], &reg);
1558c3963bc0SZev Weiss 			if (err)
1559c3963bc0SZev Weiss 				goto out;
1560c3963bc0SZev Weiss 			data->rpm[i] = data->fan_from_reg(reg,
1561c3963bc0SZev Weiss 							  data->fan_div[i]);
1562c3963bc0SZev Weiss 
1563c3963bc0SZev Weiss 			if (data->has_fan_min & BIT(i)) {
1564c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_FAN_MIN[i], &reg);
1565c3963bc0SZev Weiss 				if (err)
1566c3963bc0SZev Weiss 					goto out;
1567c3963bc0SZev Weiss 				data->fan_min[i] = reg;
1568c3963bc0SZev Weiss 			}
1569c3963bc0SZev Weiss 
1570c3963bc0SZev Weiss 			if (data->REG_FAN_PULSES[i]) {
1571c3963bc0SZev Weiss 				err = nct6775_read_value(data, data->REG_FAN_PULSES[i], &reg);
1572c3963bc0SZev Weiss 				if (err)
1573c3963bc0SZev Weiss 					goto out;
1574c3963bc0SZev Weiss 				data->fan_pulses[i] = (reg >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1575c3963bc0SZev Weiss 			}
1576c3963bc0SZev Weiss 
1577c3963bc0SZev Weiss 			err = nct6775_select_fan_div(dev, data, i, reg);
1578c3963bc0SZev Weiss 			if (err)
1579c3963bc0SZev Weiss 				goto out;
1580c3963bc0SZev Weiss 		}
1581c3963bc0SZev Weiss 
1582c3963bc0SZev Weiss 		err = nct6775_update_pwm(dev);
1583c3963bc0SZev Weiss 		if (err)
1584c3963bc0SZev Weiss 			goto out;
1585c3963bc0SZev Weiss 
1586c3963bc0SZev Weiss 		err = nct6775_update_pwm_limits(dev);
1587c3963bc0SZev Weiss 		if (err)
1588c3963bc0SZev Weiss 			goto out;
1589c3963bc0SZev Weiss 
1590c3963bc0SZev Weiss 		/* Measured temperatures and limits */
1591c3963bc0SZev Weiss 		for (i = 0; i < NUM_TEMP; i++) {
1592c3963bc0SZev Weiss 			if (!(data->have_temp & BIT(i)))
1593c3963bc0SZev Weiss 				continue;
1594c3963bc0SZev Weiss 			for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
1595c3963bc0SZev Weiss 				if (data->reg_temp[j][i]) {
1596c3963bc0SZev Weiss 					err = nct6775_read_temp(data, data->reg_temp[j][i], &reg);
1597c3963bc0SZev Weiss 					if (err)
1598c3963bc0SZev Weiss 						goto out;
1599c3963bc0SZev Weiss 					data->temp[j][i] = reg;
1600c3963bc0SZev Weiss 				}
1601c3963bc0SZev Weiss 			}
1602c3963bc0SZev Weiss 			if (i >= NUM_TEMP_FIXED ||
1603c3963bc0SZev Weiss 			    !(data->have_temp_fixed & BIT(i)))
1604c3963bc0SZev Weiss 				continue;
1605c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_TEMP_OFFSET[i], &reg);
1606c3963bc0SZev Weiss 			if (err)
1607c3963bc0SZev Weiss 				goto out;
1608c3963bc0SZev Weiss 			data->temp_offset[i] = reg;
1609c3963bc0SZev Weiss 		}
1610c3963bc0SZev Weiss 
1611c3963bc0SZev Weiss 		for (i = 0; i < NUM_TSI_TEMP; i++) {
1612c3963bc0SZev Weiss 			if (!(data->have_tsi_temp & BIT(i)))
1613c3963bc0SZev Weiss 				continue;
1614c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_TSI_TEMP[i], &reg);
1615c3963bc0SZev Weiss 			if (err)
1616c3963bc0SZev Weiss 				goto out;
1617c3963bc0SZev Weiss 			data->tsi_temp[i] = reg;
1618c3963bc0SZev Weiss 		}
1619c3963bc0SZev Weiss 
1620c3963bc0SZev Weiss 		data->alarms = 0;
1621c3963bc0SZev Weiss 		for (i = 0; i < NUM_REG_ALARM; i++) {
1622c3963bc0SZev Weiss 			u16 alarm;
1623c3963bc0SZev Weiss 
1624c3963bc0SZev Weiss 			if (!data->REG_ALARM[i])
1625c3963bc0SZev Weiss 				continue;
1626c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_ALARM[i], &alarm);
1627c3963bc0SZev Weiss 			if (err)
1628c3963bc0SZev Weiss 				goto out;
1629c3963bc0SZev Weiss 			data->alarms |= ((u64)alarm) << (i << 3);
1630c3963bc0SZev Weiss 		}
1631c3963bc0SZev Weiss 
1632c3963bc0SZev Weiss 		data->beeps = 0;
1633c3963bc0SZev Weiss 		for (i = 0; i < NUM_REG_BEEP; i++) {
1634c3963bc0SZev Weiss 			u16 beep;
1635c3963bc0SZev Weiss 
1636c3963bc0SZev Weiss 			if (!data->REG_BEEP[i])
1637c3963bc0SZev Weiss 				continue;
1638c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_BEEP[i], &beep);
1639c3963bc0SZev Weiss 			if (err)
1640c3963bc0SZev Weiss 				goto out;
1641c3963bc0SZev Weiss 			data->beeps |= ((u64)beep) << (i << 3);
1642c3963bc0SZev Weiss 		}
1643c3963bc0SZev Weiss 
1644c3963bc0SZev Weiss 		data->last_updated = jiffies;
1645c3963bc0SZev Weiss 		data->valid = true;
1646c3963bc0SZev Weiss 	}
1647c3963bc0SZev Weiss out:
1648c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
1649c3963bc0SZev Weiss 	return err ? ERR_PTR(err) : data;
1650c3963bc0SZev Weiss }
1651f4e6960fSZev Weiss EXPORT_SYMBOL_GPL(nct6775_update_device);
1652c3963bc0SZev Weiss 
1653c3963bc0SZev Weiss /*
1654c3963bc0SZev Weiss  * Sysfs callback functions
1655c3963bc0SZev Weiss  */
1656c3963bc0SZev Weiss static ssize_t
1657c3963bc0SZev Weiss show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1658c3963bc0SZev Weiss {
1659c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1660c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1661c3963bc0SZev Weiss 	int index = sattr->index;
1662c3963bc0SZev Weiss 	int nr = sattr->nr;
1663c3963bc0SZev Weiss 
1664c3963bc0SZev Weiss 	if (IS_ERR(data))
1665c3963bc0SZev Weiss 		return PTR_ERR(data);
1666c3963bc0SZev Weiss 
166713558a2eSAhmad Khalifa 	return sprintf(buf, "%ld\n",
166813558a2eSAhmad Khalifa 		       in_from_reg(data->in[nr][index], nr, data->scale_in));
1669c3963bc0SZev Weiss }
1670c3963bc0SZev Weiss 
1671c3963bc0SZev Weiss static ssize_t
1672c3963bc0SZev Weiss store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1673c3963bc0SZev Weiss 	     size_t count)
1674c3963bc0SZev Weiss {
1675c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1676c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1677c3963bc0SZev Weiss 	int index = sattr->index;
1678c3963bc0SZev Weiss 	int nr = sattr->nr;
1679c3963bc0SZev Weiss 	unsigned long val;
1680c3963bc0SZev Weiss 	int err;
1681c3963bc0SZev Weiss 
1682c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
1683c3963bc0SZev Weiss 	if (err < 0)
1684c3963bc0SZev Weiss 		return err;
1685c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
168613558a2eSAhmad Khalifa 	data->in[nr][index] = in_to_reg(val, nr, data->scale_in);
1687c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr], data->in[nr][index]);
1688c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
1689c3963bc0SZev Weiss 	return err ? : count;
1690c3963bc0SZev Weiss }
1691c3963bc0SZev Weiss 
1692c3963bc0SZev Weiss ssize_t
1693c3963bc0SZev Weiss nct6775_show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1694c3963bc0SZev Weiss {
1695c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1696c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1697c3963bc0SZev Weiss 	int nr;
1698c3963bc0SZev Weiss 
1699c3963bc0SZev Weiss 	if (IS_ERR(data))
1700c3963bc0SZev Weiss 		return PTR_ERR(data);
1701c3963bc0SZev Weiss 
1702c3963bc0SZev Weiss 	nr = data->ALARM_BITS[sattr->index];
1703c3963bc0SZev Weiss 	return sprintf(buf, "%u\n",
1704c3963bc0SZev Weiss 		       (unsigned int)((data->alarms >> nr) & 0x01));
1705c3963bc0SZev Weiss }
1706c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_show_alarm);
1707c3963bc0SZev Weiss 
1708c3963bc0SZev Weiss static int find_temp_source(struct nct6775_data *data, int index, int count)
1709c3963bc0SZev Weiss {
1710c3963bc0SZev Weiss 	int source = data->temp_src[index];
1711c3963bc0SZev Weiss 	int nr, err;
1712c3963bc0SZev Weiss 
1713c3963bc0SZev Weiss 	for (nr = 0; nr < count; nr++) {
1714c3963bc0SZev Weiss 		u16 src;
1715c3963bc0SZev Weiss 
1716c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SOURCE[nr], &src);
1717c3963bc0SZev Weiss 		if (err)
1718c3963bc0SZev Weiss 			return err;
1719c3963bc0SZev Weiss 		if ((src & 0x1f) == source)
1720c3963bc0SZev Weiss 			return nr;
1721c3963bc0SZev Weiss 	}
1722c3963bc0SZev Weiss 	return -ENODEV;
1723c3963bc0SZev Weiss }
1724c3963bc0SZev Weiss 
1725c3963bc0SZev Weiss static ssize_t
1726c3963bc0SZev Weiss show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1727c3963bc0SZev Weiss {
1728c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1729c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1730c3963bc0SZev Weiss 	unsigned int alarm = 0;
1731c3963bc0SZev Weiss 	int nr;
1732c3963bc0SZev Weiss 
1733c3963bc0SZev Weiss 	if (IS_ERR(data))
1734c3963bc0SZev Weiss 		return PTR_ERR(data);
1735c3963bc0SZev Weiss 
1736c3963bc0SZev Weiss 	/*
1737c3963bc0SZev Weiss 	 * For temperatures, there is no fixed mapping from registers to alarm
1738c3963bc0SZev Weiss 	 * bits. Alarm bits are determined by the temperature source mapping.
1739c3963bc0SZev Weiss 	 */
1740c3963bc0SZev Weiss 	nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1741c3963bc0SZev Weiss 	if (nr >= 0) {
1742c3963bc0SZev Weiss 		int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
1743c3963bc0SZev Weiss 
1744c3963bc0SZev Weiss 		alarm = (data->alarms >> bit) & 0x01;
1745c3963bc0SZev Weiss 	}
1746c3963bc0SZev Weiss 	return sprintf(buf, "%u\n", alarm);
1747c3963bc0SZev Weiss }
1748c3963bc0SZev Weiss 
1749c3963bc0SZev Weiss ssize_t
1750c3963bc0SZev Weiss nct6775_show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1751c3963bc0SZev Weiss {
1752c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1753c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1754c3963bc0SZev Weiss 	int nr;
1755c3963bc0SZev Weiss 
1756c3963bc0SZev Weiss 	if (IS_ERR(data))
1757c3963bc0SZev Weiss 		return PTR_ERR(data);
1758c3963bc0SZev Weiss 
1759c3963bc0SZev Weiss 	nr = data->BEEP_BITS[sattr->index];
1760c3963bc0SZev Weiss 
1761c3963bc0SZev Weiss 	return sprintf(buf, "%u\n",
1762c3963bc0SZev Weiss 		       (unsigned int)((data->beeps >> nr) & 0x01));
1763c3963bc0SZev Weiss }
1764c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_show_beep);
1765c3963bc0SZev Weiss 
1766c3963bc0SZev Weiss ssize_t
1767c3963bc0SZev Weiss nct6775_store_beep(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1768c3963bc0SZev Weiss {
1769c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1770c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1771c3963bc0SZev Weiss 	int nr = data->BEEP_BITS[sattr->index];
1772c3963bc0SZev Weiss 	int regindex = nr >> 3;
1773c3963bc0SZev Weiss 	unsigned long val;
1774c3963bc0SZev Weiss 	int err;
1775c3963bc0SZev Weiss 
1776c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
1777c3963bc0SZev Weiss 	if (err < 0)
1778c3963bc0SZev Weiss 		return err;
1779c3963bc0SZev Weiss 	if (val > 1)
1780c3963bc0SZev Weiss 		return -EINVAL;
1781c3963bc0SZev Weiss 
1782c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
1783c3963bc0SZev Weiss 	if (val)
1784c3963bc0SZev Weiss 		data->beeps |= (1ULL << nr);
1785c3963bc0SZev Weiss 	else
1786c3963bc0SZev Weiss 		data->beeps &= ~(1ULL << nr);
1787c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_BEEP[regindex],
1788c3963bc0SZev Weiss 				  (data->beeps >> (regindex << 3)) & 0xff);
1789c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
1790c3963bc0SZev Weiss 	return err ? : count;
1791c3963bc0SZev Weiss }
1792c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_store_beep);
1793c3963bc0SZev Weiss 
1794c3963bc0SZev Weiss static ssize_t
1795c3963bc0SZev Weiss show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1796c3963bc0SZev Weiss {
1797c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1798c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1799c3963bc0SZev Weiss 	unsigned int beep = 0;
1800c3963bc0SZev Weiss 	int nr;
1801c3963bc0SZev Weiss 
1802c3963bc0SZev Weiss 	if (IS_ERR(data))
1803c3963bc0SZev Weiss 		return PTR_ERR(data);
1804c3963bc0SZev Weiss 
1805c3963bc0SZev Weiss 	/*
1806c3963bc0SZev Weiss 	 * For temperatures, there is no fixed mapping from registers to beep
1807c3963bc0SZev Weiss 	 * enable bits. Beep enable bits are determined by the temperature
1808c3963bc0SZev Weiss 	 * source mapping.
1809c3963bc0SZev Weiss 	 */
1810c3963bc0SZev Weiss 	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1811c3963bc0SZev Weiss 	if (nr >= 0) {
1812c3963bc0SZev Weiss 		int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1813c3963bc0SZev Weiss 
1814c3963bc0SZev Weiss 		beep = (data->beeps >> bit) & 0x01;
1815c3963bc0SZev Weiss 	}
1816c3963bc0SZev Weiss 	return sprintf(buf, "%u\n", beep);
1817c3963bc0SZev Weiss }
1818c3963bc0SZev Weiss 
1819c3963bc0SZev Weiss static ssize_t
1820c3963bc0SZev Weiss store_temp_beep(struct device *dev, struct device_attribute *attr,
1821c3963bc0SZev Weiss 		const char *buf, size_t count)
1822c3963bc0SZev Weiss {
1823c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1824c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1825c3963bc0SZev Weiss 	int nr, bit, regindex;
1826c3963bc0SZev Weiss 	unsigned long val;
1827c3963bc0SZev Weiss 	int err;
1828c3963bc0SZev Weiss 
1829c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
1830c3963bc0SZev Weiss 	if (err < 0)
1831c3963bc0SZev Weiss 		return err;
1832c3963bc0SZev Weiss 	if (val > 1)
1833c3963bc0SZev Weiss 		return -EINVAL;
1834c3963bc0SZev Weiss 
1835c3963bc0SZev Weiss 	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1836c3963bc0SZev Weiss 	if (nr < 0)
1837c3963bc0SZev Weiss 		return nr;
1838c3963bc0SZev Weiss 
1839c3963bc0SZev Weiss 	bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1840c3963bc0SZev Weiss 	regindex = bit >> 3;
1841c3963bc0SZev Weiss 
1842c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
1843c3963bc0SZev Weiss 	if (val)
1844c3963bc0SZev Weiss 		data->beeps |= (1ULL << bit);
1845c3963bc0SZev Weiss 	else
1846c3963bc0SZev Weiss 		data->beeps &= ~(1ULL << bit);
1847c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_BEEP[regindex],
1848c3963bc0SZev Weiss 				  (data->beeps >> (regindex << 3)) & 0xff);
1849c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
1850c3963bc0SZev Weiss 
1851c3963bc0SZev Weiss 	return err ? : count;
1852c3963bc0SZev Weiss }
1853c3963bc0SZev Weiss 
1854c3963bc0SZev Weiss static umode_t nct6775_in_is_visible(struct kobject *kobj,
1855c3963bc0SZev Weiss 				     struct attribute *attr, int index)
1856c3963bc0SZev Weiss {
1857c3963bc0SZev Weiss 	struct device *dev = kobj_to_dev(kobj);
1858c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1859c3963bc0SZev Weiss 	int in = index / 5;	/* voltage index */
1860c3963bc0SZev Weiss 
1861c3963bc0SZev Weiss 	if (!(data->have_in & BIT(in)))
1862c3963bc0SZev Weiss 		return 0;
1863c3963bc0SZev Weiss 
1864c3963bc0SZev Weiss 	return nct6775_attr_mode(data, attr);
1865c3963bc0SZev Weiss }
1866c3963bc0SZev Weiss 
1867c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_input, "in%d_input", 0444, show_in_reg, NULL, 0, 0);
1868c3963bc0SZev Weiss SENSOR_TEMPLATE(in_alarm, "in%d_alarm", 0444, nct6775_show_alarm, NULL, 0);
1869c3963bc0SZev Weiss SENSOR_TEMPLATE(in_beep, "in%d_beep", 0644, nct6775_show_beep, nct6775_store_beep, 0);
1870c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_min, "in%d_min", 0644, show_in_reg, store_in_reg, 0, 1);
1871c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_max, "in%d_max", 0644, show_in_reg, store_in_reg, 0, 2);
1872c3963bc0SZev Weiss 
1873c3963bc0SZev Weiss /*
1874c3963bc0SZev Weiss  * nct6775_in_is_visible uses the index into the following array
1875c3963bc0SZev Weiss  * to determine if attributes should be created or not.
1876c3963bc0SZev Weiss  * Any change in order or content must be matched.
1877c3963bc0SZev Weiss  */
1878c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_in_template[] = {
1879c3963bc0SZev Weiss 	&sensor_dev_template_in_input,
1880c3963bc0SZev Weiss 	&sensor_dev_template_in_alarm,
1881c3963bc0SZev Weiss 	&sensor_dev_template_in_beep,
1882c3963bc0SZev Weiss 	&sensor_dev_template_in_min,
1883c3963bc0SZev Weiss 	&sensor_dev_template_in_max,
1884c3963bc0SZev Weiss 	NULL
1885c3963bc0SZev Weiss };
1886c3963bc0SZev Weiss 
1887c3963bc0SZev Weiss static const struct sensor_template_group nct6775_in_template_group = {
1888c3963bc0SZev Weiss 	.templates = nct6775_attributes_in_template,
1889c3963bc0SZev Weiss 	.is_visible = nct6775_in_is_visible,
1890c3963bc0SZev Weiss };
1891c3963bc0SZev Weiss 
1892c3963bc0SZev Weiss static ssize_t
1893c3963bc0SZev Weiss show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1894c3963bc0SZev Weiss {
1895c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1896c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1897c3963bc0SZev Weiss 	int nr = sattr->index;
1898c3963bc0SZev Weiss 
1899c3963bc0SZev Weiss 	if (IS_ERR(data))
1900c3963bc0SZev Weiss 		return PTR_ERR(data);
1901c3963bc0SZev Weiss 
1902c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->rpm[nr]);
1903c3963bc0SZev Weiss }
1904c3963bc0SZev Weiss 
1905c3963bc0SZev Weiss static ssize_t
1906c3963bc0SZev Weiss show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1907c3963bc0SZev Weiss {
1908c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1909c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1910c3963bc0SZev Weiss 	int nr = sattr->index;
1911c3963bc0SZev Weiss 
1912c3963bc0SZev Weiss 	if (IS_ERR(data))
1913c3963bc0SZev Weiss 		return PTR_ERR(data);
1914c3963bc0SZev Weiss 
1915c3963bc0SZev Weiss 	return sprintf(buf, "%d\n",
1916c3963bc0SZev Weiss 		       data->fan_from_reg_min(data->fan_min[nr],
1917c3963bc0SZev Weiss 					      data->fan_div[nr]));
1918c3963bc0SZev Weiss }
1919c3963bc0SZev Weiss 
1920c3963bc0SZev Weiss static ssize_t
1921c3963bc0SZev Weiss show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1922c3963bc0SZev Weiss {
1923c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
1924c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1925c3963bc0SZev Weiss 	int nr = sattr->index;
1926c3963bc0SZev Weiss 
1927c3963bc0SZev Weiss 	if (IS_ERR(data))
1928c3963bc0SZev Weiss 		return PTR_ERR(data);
1929c3963bc0SZev Weiss 
1930c3963bc0SZev Weiss 	return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1931c3963bc0SZev Weiss }
1932c3963bc0SZev Weiss 
1933c3963bc0SZev Weiss static ssize_t
1934c3963bc0SZev Weiss store_fan_min(struct device *dev, struct device_attribute *attr,
1935c3963bc0SZev Weiss 	      const char *buf, size_t count)
1936c3963bc0SZev Weiss {
1937c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
1938c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1939c3963bc0SZev Weiss 	int nr = sattr->index;
1940c3963bc0SZev Weiss 	unsigned long val;
1941c3963bc0SZev Weiss 	unsigned int reg;
1942c3963bc0SZev Weiss 	u8 new_div;
1943c3963bc0SZev Weiss 	int err;
1944c3963bc0SZev Weiss 
1945c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
1946c3963bc0SZev Weiss 	if (err < 0)
1947c3963bc0SZev Weiss 		return err;
1948c3963bc0SZev Weiss 
1949c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
1950c3963bc0SZev Weiss 	if (!data->has_fan_div) {
1951c3963bc0SZev Weiss 		/* NCT6776F or NCT6779D; we know this is a 13 bit register */
1952c3963bc0SZev Weiss 		if (!val) {
1953c3963bc0SZev Weiss 			val = 0xff1f;
1954c3963bc0SZev Weiss 		} else {
1955c3963bc0SZev Weiss 			if (val > 1350000U)
1956c3963bc0SZev Weiss 				val = 135000U;
1957c3963bc0SZev Weiss 			val = 1350000U / val;
1958c3963bc0SZev Weiss 			val = (val & 0x1f) | ((val << 3) & 0xff00);
1959c3963bc0SZev Weiss 		}
1960c3963bc0SZev Weiss 		data->fan_min[nr] = val;
1961c3963bc0SZev Weiss 		goto write_min;	/* Leave fan divider alone */
1962c3963bc0SZev Weiss 	}
1963c3963bc0SZev Weiss 	if (!val) {
1964c3963bc0SZev Weiss 		/* No min limit, alarm disabled */
1965c3963bc0SZev Weiss 		data->fan_min[nr] = 255;
1966c3963bc0SZev Weiss 		new_div = data->fan_div[nr]; /* No change */
1967c3963bc0SZev Weiss 		dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1968c3963bc0SZev Weiss 		goto write_div;
1969c3963bc0SZev Weiss 	}
1970c3963bc0SZev Weiss 	reg = 1350000U / val;
1971c3963bc0SZev Weiss 	if (reg >= 128 * 255) {
1972c3963bc0SZev Weiss 		/*
1973c3963bc0SZev Weiss 		 * Speed below this value cannot possibly be represented,
1974c3963bc0SZev Weiss 		 * even with the highest divider (128)
1975c3963bc0SZev Weiss 		 */
1976c3963bc0SZev Weiss 		data->fan_min[nr] = 254;
1977c3963bc0SZev Weiss 		new_div = 7; /* 128 == BIT(7) */
1978c3963bc0SZev Weiss 		dev_warn(dev,
1979c3963bc0SZev Weiss 			 "fan%u low limit %lu below minimum %u, set to minimum\n",
1980c3963bc0SZev Weiss 			 nr + 1, val, data->fan_from_reg_min(254, 7));
1981c3963bc0SZev Weiss 	} else if (!reg) {
1982c3963bc0SZev Weiss 		/*
1983c3963bc0SZev Weiss 		 * Speed above this value cannot possibly be represented,
1984c3963bc0SZev Weiss 		 * even with the lowest divider (1)
1985c3963bc0SZev Weiss 		 */
1986c3963bc0SZev Weiss 		data->fan_min[nr] = 1;
1987c3963bc0SZev Weiss 		new_div = 0; /* 1 == BIT(0) */
1988c3963bc0SZev Weiss 		dev_warn(dev,
1989c3963bc0SZev Weiss 			 "fan%u low limit %lu above maximum %u, set to maximum\n",
1990c3963bc0SZev Weiss 			 nr + 1, val, data->fan_from_reg_min(1, 0));
1991c3963bc0SZev Weiss 	} else {
1992c3963bc0SZev Weiss 		/*
1993c3963bc0SZev Weiss 		 * Automatically pick the best divider, i.e. the one such
1994c3963bc0SZev Weiss 		 * that the min limit will correspond to a register value
1995c3963bc0SZev Weiss 		 * in the 96..192 range
1996c3963bc0SZev Weiss 		 */
1997c3963bc0SZev Weiss 		new_div = 0;
1998c3963bc0SZev Weiss 		while (reg > 192 && new_div < 7) {
1999c3963bc0SZev Weiss 			reg >>= 1;
2000c3963bc0SZev Weiss 			new_div++;
2001c3963bc0SZev Weiss 		}
2002c3963bc0SZev Weiss 		data->fan_min[nr] = reg;
2003c3963bc0SZev Weiss 	}
2004c3963bc0SZev Weiss 
2005c3963bc0SZev Weiss write_div:
2006c3963bc0SZev Weiss 	/*
2007c3963bc0SZev Weiss 	 * Write both the fan clock divider (if it changed) and the new
2008c3963bc0SZev Weiss 	 * fan min (unconditionally)
2009c3963bc0SZev Weiss 	 */
2010c3963bc0SZev Weiss 	if (new_div != data->fan_div[nr]) {
2011c3963bc0SZev Weiss 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2012c3963bc0SZev Weiss 			nr + 1, div_from_reg(data->fan_div[nr]),
2013c3963bc0SZev Weiss 			div_from_reg(new_div));
2014c3963bc0SZev Weiss 		data->fan_div[nr] = new_div;
2015c3963bc0SZev Weiss 		err = nct6775_write_fan_div_common(data, nr);
2016c3963bc0SZev Weiss 		if (err)
2017c3963bc0SZev Weiss 			goto write_min;
2018c3963bc0SZev Weiss 		/* Give the chip time to sample a new speed value */
2019c3963bc0SZev Weiss 		data->last_updated = jiffies;
2020c3963bc0SZev Weiss 	}
2021c3963bc0SZev Weiss 
2022c3963bc0SZev Weiss write_min:
2023c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2024c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2025c3963bc0SZev Weiss 
2026c3963bc0SZev Weiss 	return err ? : count;
2027c3963bc0SZev Weiss }
2028c3963bc0SZev Weiss 
2029c3963bc0SZev Weiss static ssize_t
2030c3963bc0SZev Weiss show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2031c3963bc0SZev Weiss {
2032c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2033c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2034c3963bc0SZev Weiss 	int p;
2035c3963bc0SZev Weiss 
2036c3963bc0SZev Weiss 	if (IS_ERR(data))
2037c3963bc0SZev Weiss 		return PTR_ERR(data);
2038c3963bc0SZev Weiss 
2039c3963bc0SZev Weiss 	p = data->fan_pulses[sattr->index];
2040c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", p ? : 4);
2041c3963bc0SZev Weiss }
2042c3963bc0SZev Weiss 
2043c3963bc0SZev Weiss static ssize_t
2044c3963bc0SZev Weiss store_fan_pulses(struct device *dev, struct device_attribute *attr,
2045c3963bc0SZev Weiss 		 const char *buf, size_t count)
2046c3963bc0SZev Weiss {
2047c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2048c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2049c3963bc0SZev Weiss 	int nr = sattr->index;
2050c3963bc0SZev Weiss 	unsigned long val;
2051c3963bc0SZev Weiss 	int err;
2052c3963bc0SZev Weiss 	u16 reg;
2053c3963bc0SZev Weiss 
2054c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2055c3963bc0SZev Weiss 	if (err < 0)
2056c3963bc0SZev Weiss 		return err;
2057c3963bc0SZev Weiss 
2058c3963bc0SZev Weiss 	if (val > 4)
2059c3963bc0SZev Weiss 		return -EINVAL;
2060c3963bc0SZev Weiss 
2061c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2062c3963bc0SZev Weiss 	data->fan_pulses[nr] = val & 3;
2063c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_FAN_PULSES[nr], &reg);
2064c3963bc0SZev Weiss 	if (err)
2065c3963bc0SZev Weiss 		goto out;
2066c3963bc0SZev Weiss 	reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2067c3963bc0SZev Weiss 	reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2068c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
2069c3963bc0SZev Weiss out:
2070c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2071c3963bc0SZev Weiss 
2072c3963bc0SZev Weiss 	return err ? : count;
2073c3963bc0SZev Weiss }
2074c3963bc0SZev Weiss 
2075c3963bc0SZev Weiss static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2076c3963bc0SZev Weiss 				      struct attribute *attr, int index)
2077c3963bc0SZev Weiss {
2078c3963bc0SZev Weiss 	struct device *dev = kobj_to_dev(kobj);
2079c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2080c3963bc0SZev Weiss 	int fan = index / 6;	/* fan index */
2081c3963bc0SZev Weiss 	int nr = index % 6;	/* attribute index */
2082c3963bc0SZev Weiss 
2083c3963bc0SZev Weiss 	if (!(data->has_fan & BIT(fan)))
2084c3963bc0SZev Weiss 		return 0;
2085c3963bc0SZev Weiss 
2086c3963bc0SZev Weiss 	if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2087c3963bc0SZev Weiss 		return 0;
2088c3963bc0SZev Weiss 	if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
2089c3963bc0SZev Weiss 		return 0;
2090c3963bc0SZev Weiss 	if (nr == 3 && !data->REG_FAN_PULSES[fan])
2091c3963bc0SZev Weiss 		return 0;
2092c3963bc0SZev Weiss 	if (nr == 4 && !(data->has_fan_min & BIT(fan)))
2093c3963bc0SZev Weiss 		return 0;
2094c3963bc0SZev Weiss 	if (nr == 5 && data->kind != nct6775)
2095c3963bc0SZev Weiss 		return 0;
2096c3963bc0SZev Weiss 
2097c3963bc0SZev Weiss 	return nct6775_attr_mode(data, attr);
2098c3963bc0SZev Weiss }
2099c3963bc0SZev Weiss 
2100c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_input, "fan%d_input", 0444, show_fan, NULL, 0);
2101c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", 0444, nct6775_show_alarm, NULL, FAN_ALARM_BASE);
2102c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_beep, "fan%d_beep", 0644, nct6775_show_beep,
2103c3963bc0SZev Weiss 		nct6775_store_beep, FAN_ALARM_BASE);
2104c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", 0644, show_fan_pulses, store_fan_pulses, 0);
2105c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_min, "fan%d_min", 0644, show_fan_min, store_fan_min, 0);
2106c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_div, "fan%d_div", 0444, show_fan_div, NULL, 0);
2107c3963bc0SZev Weiss 
2108c3963bc0SZev Weiss /*
2109c3963bc0SZev Weiss  * nct6775_fan_is_visible uses the index into the following array
2110c3963bc0SZev Weiss  * to determine if attributes should be created or not.
2111c3963bc0SZev Weiss  * Any change in order or content must be matched.
2112c3963bc0SZev Weiss  */
2113c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2114c3963bc0SZev Weiss 	&sensor_dev_template_fan_input,
2115c3963bc0SZev Weiss 	&sensor_dev_template_fan_alarm,	/* 1 */
2116c3963bc0SZev Weiss 	&sensor_dev_template_fan_beep,	/* 2 */
2117c3963bc0SZev Weiss 	&sensor_dev_template_fan_pulses,
2118c3963bc0SZev Weiss 	&sensor_dev_template_fan_min,	/* 4 */
2119c3963bc0SZev Weiss 	&sensor_dev_template_fan_div,	/* 5 */
2120c3963bc0SZev Weiss 	NULL
2121c3963bc0SZev Weiss };
2122c3963bc0SZev Weiss 
2123c3963bc0SZev Weiss static const struct sensor_template_group nct6775_fan_template_group = {
2124c3963bc0SZev Weiss 	.templates = nct6775_attributes_fan_template,
2125c3963bc0SZev Weiss 	.is_visible = nct6775_fan_is_visible,
2126c3963bc0SZev Weiss 	.base = 1,
2127c3963bc0SZev Weiss };
2128c3963bc0SZev Weiss 
2129c3963bc0SZev Weiss static ssize_t
2130c3963bc0SZev Weiss show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2131c3963bc0SZev Weiss {
2132c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2133c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2134c3963bc0SZev Weiss 	int nr = sattr->index;
2135c3963bc0SZev Weiss 
2136c3963bc0SZev Weiss 	if (IS_ERR(data))
2137c3963bc0SZev Weiss 		return PTR_ERR(data);
2138c3963bc0SZev Weiss 
2139c3963bc0SZev Weiss 	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2140c3963bc0SZev Weiss }
2141c3963bc0SZev Weiss 
2142c3963bc0SZev Weiss static ssize_t
2143c3963bc0SZev Weiss show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2144c3963bc0SZev Weiss {
2145c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2146c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2147c3963bc0SZev Weiss 	int nr = sattr->nr;
2148c3963bc0SZev Weiss 	int index = sattr->index;
2149c3963bc0SZev Weiss 
2150c3963bc0SZev Weiss 	if (IS_ERR(data))
2151c3963bc0SZev Weiss 		return PTR_ERR(data);
2152c3963bc0SZev Weiss 
2153c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2154c3963bc0SZev Weiss }
2155c3963bc0SZev Weiss 
2156c3963bc0SZev Weiss static ssize_t
2157c3963bc0SZev Weiss store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2158c3963bc0SZev Weiss 	   size_t count)
2159c3963bc0SZev Weiss {
2160c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2161c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2162c3963bc0SZev Weiss 	int nr = sattr->nr;
2163c3963bc0SZev Weiss 	int index = sattr->index;
2164c3963bc0SZev Weiss 	int err;
2165c3963bc0SZev Weiss 	long val;
2166c3963bc0SZev Weiss 
2167c3963bc0SZev Weiss 	err = kstrtol(buf, 10, &val);
2168c3963bc0SZev Weiss 	if (err < 0)
2169c3963bc0SZev Weiss 		return err;
2170c3963bc0SZev Weiss 
2171c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2172c3963bc0SZev Weiss 	data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2173c3963bc0SZev Weiss 	err = nct6775_write_temp(data, data->reg_temp[index][nr], data->temp[index][nr]);
2174c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2175c3963bc0SZev Weiss 	return err ? : count;
2176c3963bc0SZev Weiss }
2177c3963bc0SZev Weiss 
2178c3963bc0SZev Weiss static ssize_t
2179c3963bc0SZev Weiss show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2180c3963bc0SZev Weiss {
2181c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2182c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2183c3963bc0SZev Weiss 
2184c3963bc0SZev Weiss 	if (IS_ERR(data))
2185c3963bc0SZev Weiss 		return PTR_ERR(data);
2186c3963bc0SZev Weiss 
2187c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2188c3963bc0SZev Weiss }
2189c3963bc0SZev Weiss 
2190c3963bc0SZev Weiss static ssize_t
2191c3963bc0SZev Weiss store_temp_offset(struct device *dev, struct device_attribute *attr,
2192c3963bc0SZev Weiss 		  const char *buf, size_t count)
2193c3963bc0SZev Weiss {
2194c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2195c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2196c3963bc0SZev Weiss 	int nr = sattr->index;
2197c3963bc0SZev Weiss 	long val;
2198c3963bc0SZev Weiss 	int err;
2199c3963bc0SZev Weiss 
2200c3963bc0SZev Weiss 	err = kstrtol(buf, 10, &val);
2201c3963bc0SZev Weiss 	if (err < 0)
2202c3963bc0SZev Weiss 		return err;
2203c3963bc0SZev Weiss 
2204c3963bc0SZev Weiss 	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2205c3963bc0SZev Weiss 
2206c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2207c3963bc0SZev Weiss 	data->temp_offset[nr] = val;
2208c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2209c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2210c3963bc0SZev Weiss 
2211c3963bc0SZev Weiss 	return err ? : count;
2212c3963bc0SZev Weiss }
2213c3963bc0SZev Weiss 
2214c3963bc0SZev Weiss static ssize_t
2215c3963bc0SZev Weiss show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2216c3963bc0SZev Weiss {
2217c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2218c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2219c3963bc0SZev Weiss 	int nr = sattr->index;
2220c3963bc0SZev Weiss 
2221c3963bc0SZev Weiss 	if (IS_ERR(data))
2222c3963bc0SZev Weiss 		return PTR_ERR(data);
2223c3963bc0SZev Weiss 
2224c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2225c3963bc0SZev Weiss }
2226c3963bc0SZev Weiss 
2227c3963bc0SZev Weiss static ssize_t
2228c3963bc0SZev Weiss store_temp_type(struct device *dev, struct device_attribute *attr,
2229c3963bc0SZev Weiss 		const char *buf, size_t count)
2230c3963bc0SZev Weiss {
2231c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2232c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2233c3963bc0SZev Weiss 	int nr = sattr->index;
2234c3963bc0SZev Weiss 	unsigned long val;
2235c3963bc0SZev Weiss 	int err;
2236c3963bc0SZev Weiss 	u8 vbit, dbit;
2237c3963bc0SZev Weiss 	u16 vbat, diode;
2238c3963bc0SZev Weiss 
2239c3963bc0SZev Weiss 	if (IS_ERR(data))
2240c3963bc0SZev Weiss 		return PTR_ERR(data);
2241c3963bc0SZev Weiss 
2242c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2243c3963bc0SZev Weiss 	if (err < 0)
2244c3963bc0SZev Weiss 		return err;
2245c3963bc0SZev Weiss 
2246c3963bc0SZev Weiss 	if (val != 1 && val != 3 && val != 4)
2247c3963bc0SZev Weiss 		return -EINVAL;
2248c3963bc0SZev Weiss 
2249c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2250c3963bc0SZev Weiss 
2251c3963bc0SZev Weiss 	data->temp_type[nr] = val;
2252c3963bc0SZev Weiss 	vbit = 0x02 << nr;
2253c3963bc0SZev Weiss 	dbit = data->DIODE_MASK << nr;
2254c3963bc0SZev Weiss 
2255c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_VBAT, &vbat);
2256c3963bc0SZev Weiss 	if (err)
2257c3963bc0SZev Weiss 		goto out;
2258c3963bc0SZev Weiss 	vbat &= ~vbit;
2259c3963bc0SZev Weiss 
2260c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_DIODE, &diode);
2261c3963bc0SZev Weiss 	if (err)
2262c3963bc0SZev Weiss 		goto out;
2263c3963bc0SZev Weiss 	diode &= ~dbit;
2264c3963bc0SZev Weiss 
2265c3963bc0SZev Weiss 	switch (val) {
2266c3963bc0SZev Weiss 	case 1:	/* CPU diode (diode, current mode) */
2267c3963bc0SZev Weiss 		vbat |= vbit;
2268c3963bc0SZev Weiss 		diode |= dbit;
2269c3963bc0SZev Weiss 		break;
2270c3963bc0SZev Weiss 	case 3: /* diode, voltage mode */
2271c3963bc0SZev Weiss 		vbat |= dbit;
2272c3963bc0SZev Weiss 		break;
2273c3963bc0SZev Weiss 	case 4:	/* thermistor */
2274c3963bc0SZev Weiss 		break;
2275c3963bc0SZev Weiss 	}
2276c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_VBAT, vbat);
2277c3963bc0SZev Weiss 	if (err)
2278c3963bc0SZev Weiss 		goto out;
2279c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_DIODE, diode);
2280c3963bc0SZev Weiss out:
2281c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2282c3963bc0SZev Weiss 	return err ? : count;
2283c3963bc0SZev Weiss }
2284c3963bc0SZev Weiss 
2285c3963bc0SZev Weiss static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2286c3963bc0SZev Weiss 				       struct attribute *attr, int index)
2287c3963bc0SZev Weiss {
2288c3963bc0SZev Weiss 	struct device *dev = kobj_to_dev(kobj);
2289c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2290c3963bc0SZev Weiss 	int temp = index / 10;	/* temp index */
2291c3963bc0SZev Weiss 	int nr = index % 10;	/* attribute index */
2292c3963bc0SZev Weiss 
2293c3963bc0SZev Weiss 	if (!(data->have_temp & BIT(temp)))
2294c3963bc0SZev Weiss 		return 0;
2295c3963bc0SZev Weiss 
2296c3963bc0SZev Weiss 	if (nr == 1 && !data->temp_label)
2297c3963bc0SZev Weiss 		return 0;
2298c3963bc0SZev Weiss 
2299c3963bc0SZev Weiss 	if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2300c3963bc0SZev Weiss 		return 0;				/* alarm */
2301c3963bc0SZev Weiss 
2302c3963bc0SZev Weiss 	if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2303c3963bc0SZev Weiss 		return 0;				/* beep */
2304c3963bc0SZev Weiss 
2305c3963bc0SZev Weiss 	if (nr == 4 && !data->reg_temp[1][temp])	/* max */
2306c3963bc0SZev Weiss 		return 0;
2307c3963bc0SZev Weiss 
2308c3963bc0SZev Weiss 	if (nr == 5 && !data->reg_temp[2][temp])	/* max_hyst */
2309c3963bc0SZev Weiss 		return 0;
2310c3963bc0SZev Weiss 
2311c3963bc0SZev Weiss 	if (nr == 6 && !data->reg_temp[3][temp])	/* crit */
2312c3963bc0SZev Weiss 		return 0;
2313c3963bc0SZev Weiss 
2314c3963bc0SZev Weiss 	if (nr == 7 && !data->reg_temp[4][temp])	/* lcrit */
2315c3963bc0SZev Weiss 		return 0;
2316c3963bc0SZev Weiss 
2317c3963bc0SZev Weiss 	/* offset and type only apply to fixed sensors */
2318c3963bc0SZev Weiss 	if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
2319c3963bc0SZev Weiss 		return 0;
2320c3963bc0SZev Weiss 
2321c3963bc0SZev Weiss 	return nct6775_attr_mode(data, attr);
2322c3963bc0SZev Weiss }
2323c3963bc0SZev Weiss 
2324c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_input, "temp%d_input", 0444, show_temp, NULL, 0, 0);
2325c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_label, "temp%d_label", 0444, show_temp_label, NULL, 0);
2326c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_max, "temp%d_max", 0644, show_temp, store_temp, 0, 1);
2327c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", 0644, show_temp, store_temp, 0, 2);
2328c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", 0644, show_temp, store_temp, 0, 3);
2329c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", 0644, show_temp, store_temp, 0, 4);
2330c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_offset, "temp%d_offset", 0644, show_temp_offset, store_temp_offset, 0);
2331c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_type, "temp%d_type", 0644, show_temp_type, store_temp_type, 0);
2332c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", 0444, show_temp_alarm, NULL, 0);
2333c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_beep, "temp%d_beep", 0644, show_temp_beep, store_temp_beep, 0);
2334c3963bc0SZev Weiss 
2335c3963bc0SZev Weiss /*
2336c3963bc0SZev Weiss  * nct6775_temp_is_visible uses the index into the following array
2337c3963bc0SZev Weiss  * to determine if attributes should be created or not.
2338c3963bc0SZev Weiss  * Any change in order or content must be matched.
2339c3963bc0SZev Weiss  */
2340c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2341c3963bc0SZev Weiss 	&sensor_dev_template_temp_input,
2342c3963bc0SZev Weiss 	&sensor_dev_template_temp_label,
2343c3963bc0SZev Weiss 	&sensor_dev_template_temp_alarm,	/* 2 */
2344c3963bc0SZev Weiss 	&sensor_dev_template_temp_beep,		/* 3 */
2345c3963bc0SZev Weiss 	&sensor_dev_template_temp_max,		/* 4 */
2346c3963bc0SZev Weiss 	&sensor_dev_template_temp_max_hyst,	/* 5 */
2347c3963bc0SZev Weiss 	&sensor_dev_template_temp_crit,		/* 6 */
2348c3963bc0SZev Weiss 	&sensor_dev_template_temp_lcrit,	/* 7 */
2349c3963bc0SZev Weiss 	&sensor_dev_template_temp_offset,	/* 8 */
2350c3963bc0SZev Weiss 	&sensor_dev_template_temp_type,		/* 9 */
2351c3963bc0SZev Weiss 	NULL
2352c3963bc0SZev Weiss };
2353c3963bc0SZev Weiss 
2354c3963bc0SZev Weiss static const struct sensor_template_group nct6775_temp_template_group = {
2355c3963bc0SZev Weiss 	.templates = nct6775_attributes_temp_template,
2356c3963bc0SZev Weiss 	.is_visible = nct6775_temp_is_visible,
2357c3963bc0SZev Weiss 	.base = 1,
2358c3963bc0SZev Weiss };
2359c3963bc0SZev Weiss 
2360c3963bc0SZev Weiss static ssize_t show_tsi_temp(struct device *dev, struct device_attribute *attr, char *buf)
2361c3963bc0SZev Weiss {
2362c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2363c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2364c3963bc0SZev Weiss 
2365c3963bc0SZev Weiss 	if (IS_ERR(data))
2366c3963bc0SZev Weiss 		return PTR_ERR(data);
2367c3963bc0SZev Weiss 
2368c3963bc0SZev Weiss 	return sysfs_emit(buf, "%u\n", tsi_temp_from_reg(data->tsi_temp[sattr->index]));
2369c3963bc0SZev Weiss }
2370c3963bc0SZev Weiss 
2371c3963bc0SZev Weiss static ssize_t show_tsi_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2372c3963bc0SZev Weiss {
2373c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2374c3963bc0SZev Weiss 
2375c3963bc0SZev Weiss 	return sysfs_emit(buf, "TSI%d_TEMP\n", sattr->index);
2376c3963bc0SZev Weiss }
2377c3963bc0SZev Weiss 
2378c3963bc0SZev Weiss SENSOR_TEMPLATE(tsi_temp_input, "temp%d_input", 0444, show_tsi_temp, NULL, 0);
2379c3963bc0SZev Weiss SENSOR_TEMPLATE(tsi_temp_label, "temp%d_label", 0444, show_tsi_temp_label, NULL, 0);
2380c3963bc0SZev Weiss 
2381c3963bc0SZev Weiss static umode_t nct6775_tsi_temp_is_visible(struct kobject *kobj, struct attribute *attr,
2382c3963bc0SZev Weiss 					       int index)
2383c3963bc0SZev Weiss {
2384c3963bc0SZev Weiss 	struct device *dev = kobj_to_dev(kobj);
2385c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2386c3963bc0SZev Weiss 	int temp = index / 2;
2387c3963bc0SZev Weiss 
2388c3963bc0SZev Weiss 	return (data->have_tsi_temp & BIT(temp)) ? nct6775_attr_mode(data, attr) : 0;
2389c3963bc0SZev Weiss }
2390c3963bc0SZev Weiss 
2391c3963bc0SZev Weiss /*
2392c3963bc0SZev Weiss  * The index calculation in nct6775_tsi_temp_is_visible() must be kept in
2393c3963bc0SZev Weiss  * sync with the size of this array.
2394c3963bc0SZev Weiss  */
2395c3963bc0SZev Weiss static struct sensor_device_template *nct6775_tsi_temp_template[] = {
2396c3963bc0SZev Weiss 	&sensor_dev_template_tsi_temp_input,
2397c3963bc0SZev Weiss 	&sensor_dev_template_tsi_temp_label,
2398c3963bc0SZev Weiss 	NULL
2399c3963bc0SZev Weiss };
2400c3963bc0SZev Weiss 
2401c3963bc0SZev Weiss static ssize_t
2402c3963bc0SZev Weiss show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2403c3963bc0SZev Weiss {
2404c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2405c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2406c3963bc0SZev Weiss 
2407c3963bc0SZev Weiss 	if (IS_ERR(data))
2408c3963bc0SZev Weiss 		return PTR_ERR(data);
2409c3963bc0SZev Weiss 
2410c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
2411c3963bc0SZev Weiss }
2412c3963bc0SZev Weiss 
2413c3963bc0SZev Weiss static ssize_t
2414c3963bc0SZev Weiss store_pwm_mode(struct device *dev, struct device_attribute *attr,
2415c3963bc0SZev Weiss 	       const char *buf, size_t count)
2416c3963bc0SZev Weiss {
2417c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2418c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2419c3963bc0SZev Weiss 	int nr = sattr->index;
2420c3963bc0SZev Weiss 	unsigned long val;
2421c3963bc0SZev Weiss 	int err;
2422c3963bc0SZev Weiss 	u16 reg;
2423c3963bc0SZev Weiss 
2424c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2425c3963bc0SZev Weiss 	if (err < 0)
2426c3963bc0SZev Weiss 		return err;
2427c3963bc0SZev Weiss 
2428c3963bc0SZev Weiss 	if (val > 1)
2429c3963bc0SZev Weiss 		return -EINVAL;
2430c3963bc0SZev Weiss 
2431c3963bc0SZev Weiss 	/* Setting DC mode (0) is not supported for all chips/channels */
2432c3963bc0SZev Weiss 	if (data->REG_PWM_MODE[nr] == 0) {
2433c3963bc0SZev Weiss 		if (!val)
2434c3963bc0SZev Weiss 			return -EINVAL;
2435c3963bc0SZev Weiss 		return count;
2436c3963bc0SZev Weiss 	}
2437c3963bc0SZev Weiss 
2438c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2439c3963bc0SZev Weiss 	data->pwm_mode[nr] = val;
2440c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_PWM_MODE[nr], &reg);
2441c3963bc0SZev Weiss 	if (err)
2442c3963bc0SZev Weiss 		goto out;
2443c3963bc0SZev Weiss 	reg &= ~data->PWM_MODE_MASK[nr];
2444c3963bc0SZev Weiss 	if (!val)
2445c3963bc0SZev Weiss 		reg |= data->PWM_MODE_MASK[nr];
2446c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2447c3963bc0SZev Weiss out:
2448c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2449c3963bc0SZev Weiss 	return err ? : count;
2450c3963bc0SZev Weiss }
2451c3963bc0SZev Weiss 
2452c3963bc0SZev Weiss static ssize_t
2453c3963bc0SZev Weiss show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2454c3963bc0SZev Weiss {
2455c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2456c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2457c3963bc0SZev Weiss 	int nr = sattr->nr;
2458c3963bc0SZev Weiss 	int index = sattr->index;
2459c3963bc0SZev Weiss 	int err;
2460c3963bc0SZev Weiss 	u16 pwm;
2461c3963bc0SZev Weiss 
2462c3963bc0SZev Weiss 	if (IS_ERR(data))
2463c3963bc0SZev Weiss 		return PTR_ERR(data);
2464c3963bc0SZev Weiss 
2465c3963bc0SZev Weiss 	/*
2466c3963bc0SZev Weiss 	 * For automatic fan control modes, show current pwm readings.
2467c3963bc0SZev Weiss 	 * Otherwise, show the configured value.
2468c3963bc0SZev Weiss 	 */
2469c3963bc0SZev Weiss 	if (index == 0 && data->pwm_enable[nr] > manual) {
2470c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_PWM_READ[nr], &pwm);
2471c3963bc0SZev Weiss 		if (err)
2472c3963bc0SZev Weiss 			return err;
2473c3963bc0SZev Weiss 	} else {
2474c3963bc0SZev Weiss 		pwm = data->pwm[index][nr];
2475c3963bc0SZev Weiss 	}
2476c3963bc0SZev Weiss 
2477c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", pwm);
2478c3963bc0SZev Weiss }
2479c3963bc0SZev Weiss 
2480c3963bc0SZev Weiss static ssize_t
2481c3963bc0SZev Weiss store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2482c3963bc0SZev Weiss 	  size_t count)
2483c3963bc0SZev Weiss {
2484c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2485c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2486c3963bc0SZev Weiss 	int nr = sattr->nr;
2487c3963bc0SZev Weiss 	int index = sattr->index;
2488c3963bc0SZev Weiss 	unsigned long val;
2489c3963bc0SZev Weiss 	int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2490c3963bc0SZev Weiss 	int maxval[7]
2491c3963bc0SZev Weiss 	  = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
2492c3963bc0SZev Weiss 	int err;
2493c3963bc0SZev Weiss 	u16 reg;
2494c3963bc0SZev Weiss 
2495c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2496c3963bc0SZev Weiss 	if (err < 0)
2497c3963bc0SZev Weiss 		return err;
2498c3963bc0SZev Weiss 	val = clamp_val(val, minval[index], maxval[index]);
2499c3963bc0SZev Weiss 
2500c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2501c3963bc0SZev Weiss 	data->pwm[index][nr] = val;
2502c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_PWM[index][nr], val);
2503c3963bc0SZev Weiss 	if (err)
2504c3963bc0SZev Weiss 		goto out;
2505c3963bc0SZev Weiss 	if (index == 2)	{ /* floor: disable if val == 0 */
2506c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SEL[nr], &reg);
2507c3963bc0SZev Weiss 		if (err)
2508c3963bc0SZev Weiss 			goto out;
2509c3963bc0SZev Weiss 		reg &= 0x7f;
2510c3963bc0SZev Weiss 		if (val)
2511c3963bc0SZev Weiss 			reg |= 0x80;
2512c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2513c3963bc0SZev Weiss 	}
2514c3963bc0SZev Weiss out:
2515c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2516c3963bc0SZev Weiss 	return err ? : count;
2517c3963bc0SZev Weiss }
2518c3963bc0SZev Weiss 
2519c3963bc0SZev Weiss /* Returns 0 if OK, -EINVAL otherwise */
2520c3963bc0SZev Weiss static int check_trip_points(struct nct6775_data *data, int nr)
2521c3963bc0SZev Weiss {
2522c3963bc0SZev Weiss 	int i;
2523c3963bc0SZev Weiss 
2524c3963bc0SZev Weiss 	for (i = 0; i < data->auto_pwm_num - 1; i++) {
2525c3963bc0SZev Weiss 		if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2526c3963bc0SZev Weiss 			return -EINVAL;
2527c3963bc0SZev Weiss 	}
2528c3963bc0SZev Weiss 	for (i = 0; i < data->auto_pwm_num - 1; i++) {
2529c3963bc0SZev Weiss 		if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2530c3963bc0SZev Weiss 			return -EINVAL;
2531c3963bc0SZev Weiss 	}
2532c3963bc0SZev Weiss 	/* validate critical temperature and pwm if enabled (pwm > 0) */
2533c3963bc0SZev Weiss 	if (data->auto_pwm[nr][data->auto_pwm_num]) {
2534c3963bc0SZev Weiss 		if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2535c3963bc0SZev Weiss 				data->auto_temp[nr][data->auto_pwm_num] ||
2536c3963bc0SZev Weiss 		    data->auto_pwm[nr][data->auto_pwm_num - 1] >
2537c3963bc0SZev Weiss 				data->auto_pwm[nr][data->auto_pwm_num])
2538c3963bc0SZev Weiss 			return -EINVAL;
2539c3963bc0SZev Weiss 	}
2540c3963bc0SZev Weiss 	return 0;
2541c3963bc0SZev Weiss }
2542c3963bc0SZev Weiss 
2543c3963bc0SZev Weiss static int pwm_update_registers(struct nct6775_data *data, int nr)
2544c3963bc0SZev Weiss {
2545c3963bc0SZev Weiss 	u16 reg;
2546c3963bc0SZev Weiss 	int err;
2547c3963bc0SZev Weiss 
2548c3963bc0SZev Weiss 	switch (data->pwm_enable[nr]) {
2549c3963bc0SZev Weiss 	case off:
2550c3963bc0SZev Weiss 	case manual:
2551c3963bc0SZev Weiss 		break;
2552c3963bc0SZev Weiss 	case speed_cruise:
2553c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_FAN_MODE[nr], &reg);
2554c3963bc0SZev Weiss 		if (err)
2555c3963bc0SZev Weiss 			return err;
2556c3963bc0SZev Weiss 		reg = (reg & ~data->tolerance_mask) |
2557c3963bc0SZev Weiss 		  (data->target_speed_tolerance[nr] & data->tolerance_mask);
2558c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2559c3963bc0SZev Weiss 		if (err)
2560c3963bc0SZev Weiss 			return err;
2561c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_TARGET[nr],
2562c3963bc0SZev Weiss 					  data->target_speed[nr] & 0xff);
2563c3963bc0SZev Weiss 		if (err)
2564c3963bc0SZev Weiss 			return err;
2565c3963bc0SZev Weiss 		if (data->REG_TOLERANCE_H) {
2566c3963bc0SZev Weiss 			reg = (data->target_speed[nr] >> 8) & 0x0f;
2567c3963bc0SZev Weiss 			reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2568c3963bc0SZev Weiss 			err = nct6775_write_value(data, data->REG_TOLERANCE_H[nr], reg);
2569c3963bc0SZev Weiss 			if (err)
2570c3963bc0SZev Weiss 				return err;
2571c3963bc0SZev Weiss 		}
2572c3963bc0SZev Weiss 		break;
2573c3963bc0SZev Weiss 	case thermal_cruise:
2574c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_TARGET[nr], data->target_temp[nr]);
2575c3963bc0SZev Weiss 		if (err)
2576c3963bc0SZev Weiss 			return err;
2577c3963bc0SZev Weiss 		fallthrough;
2578c3963bc0SZev Weiss 	default:
2579c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_FAN_MODE[nr], &reg);
2580c3963bc0SZev Weiss 		if (err)
2581c3963bc0SZev Weiss 			return err;
2582c3963bc0SZev Weiss 		reg = (reg & ~data->tolerance_mask) |
2583c3963bc0SZev Weiss 		  data->temp_tolerance[0][nr];
2584c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2585c3963bc0SZev Weiss 		if (err)
2586c3963bc0SZev Weiss 			return err;
2587c3963bc0SZev Weiss 		break;
2588c3963bc0SZev Weiss 	}
2589c3963bc0SZev Weiss 
2590c3963bc0SZev Weiss 	return 0;
2591c3963bc0SZev Weiss }
2592c3963bc0SZev Weiss 
2593c3963bc0SZev Weiss static ssize_t
2594c3963bc0SZev Weiss show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2595c3963bc0SZev Weiss {
2596c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2597c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2598c3963bc0SZev Weiss 
2599c3963bc0SZev Weiss 	if (IS_ERR(data))
2600c3963bc0SZev Weiss 		return PTR_ERR(data);
2601c3963bc0SZev Weiss 
2602c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2603c3963bc0SZev Weiss }
2604c3963bc0SZev Weiss 
2605c3963bc0SZev Weiss static ssize_t
2606c3963bc0SZev Weiss store_pwm_enable(struct device *dev, struct device_attribute *attr,
2607c3963bc0SZev Weiss 		 const char *buf, size_t count)
2608c3963bc0SZev Weiss {
2609c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2610c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2611c3963bc0SZev Weiss 	int nr = sattr->index;
2612c3963bc0SZev Weiss 	unsigned long val;
2613c3963bc0SZev Weiss 	int err;
2614c3963bc0SZev Weiss 	u16 reg;
2615c3963bc0SZev Weiss 
2616c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2617c3963bc0SZev Weiss 	if (err < 0)
2618c3963bc0SZev Weiss 		return err;
2619c3963bc0SZev Weiss 
2620c3963bc0SZev Weiss 	if (val > sf4)
2621c3963bc0SZev Weiss 		return -EINVAL;
2622c3963bc0SZev Weiss 
2623c3963bc0SZev Weiss 	if (val == sf3 && data->kind != nct6775)
2624c3963bc0SZev Weiss 		return -EINVAL;
2625c3963bc0SZev Weiss 
2626c3963bc0SZev Weiss 	if (val == sf4 && check_trip_points(data, nr)) {
2627c3963bc0SZev Weiss 		dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2628c3963bc0SZev Weiss 		dev_err(dev, "Adjust trip points and try again\n");
2629c3963bc0SZev Weiss 		return -EINVAL;
2630c3963bc0SZev Weiss 	}
2631c3963bc0SZev Weiss 
2632c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2633c3963bc0SZev Weiss 	data->pwm_enable[nr] = val;
2634c3963bc0SZev Weiss 	if (val == off) {
2635c3963bc0SZev Weiss 		/*
2636c3963bc0SZev Weiss 		 * turn off pwm control: select manual mode, set pwm to maximum
2637c3963bc0SZev Weiss 		 */
2638c3963bc0SZev Weiss 		data->pwm[0][nr] = 255;
2639c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2640c3963bc0SZev Weiss 		if (err)
2641c3963bc0SZev Weiss 			goto out;
2642c3963bc0SZev Weiss 	}
2643c3963bc0SZev Weiss 	err = pwm_update_registers(data, nr);
2644c3963bc0SZev Weiss 	if (err)
2645c3963bc0SZev Weiss 		goto out;
2646c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_FAN_MODE[nr], &reg);
2647c3963bc0SZev Weiss 	if (err)
2648c3963bc0SZev Weiss 		goto out;
2649c3963bc0SZev Weiss 	reg &= 0x0f;
2650c3963bc0SZev Weiss 	reg |= pwm_enable_to_reg(val) << 4;
2651c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2652c3963bc0SZev Weiss out:
2653c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2654c3963bc0SZev Weiss 	return err ? : count;
2655c3963bc0SZev Weiss }
2656c3963bc0SZev Weiss 
2657c3963bc0SZev Weiss static ssize_t
2658c3963bc0SZev Weiss show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
2659c3963bc0SZev Weiss {
2660c3963bc0SZev Weiss 	int i, sel = 0;
2661c3963bc0SZev Weiss 
2662c3963bc0SZev Weiss 	for (i = 0; i < NUM_TEMP; i++) {
2663c3963bc0SZev Weiss 		if (!(data->have_temp & BIT(i)))
2664c3963bc0SZev Weiss 			continue;
2665c3963bc0SZev Weiss 		if (src == data->temp_src[i]) {
2666c3963bc0SZev Weiss 			sel = i + 1;
2667c3963bc0SZev Weiss 			break;
2668c3963bc0SZev Weiss 		}
2669c3963bc0SZev Weiss 	}
2670c3963bc0SZev Weiss 
2671c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", sel);
2672c3963bc0SZev Weiss }
2673c3963bc0SZev Weiss 
2674c3963bc0SZev Weiss static ssize_t
2675c3963bc0SZev Weiss show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2676c3963bc0SZev Weiss {
2677c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2678c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2679c3963bc0SZev Weiss 	int index = sattr->index;
2680c3963bc0SZev Weiss 
2681c3963bc0SZev Weiss 	if (IS_ERR(data))
2682c3963bc0SZev Weiss 		return PTR_ERR(data);
2683c3963bc0SZev Weiss 
2684c3963bc0SZev Weiss 	return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2685c3963bc0SZev Weiss }
2686c3963bc0SZev Weiss 
2687c3963bc0SZev Weiss static ssize_t
2688c3963bc0SZev Weiss store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2689c3963bc0SZev Weiss 		   const char *buf, size_t count)
2690c3963bc0SZev Weiss {
2691c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2692c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2693c3963bc0SZev Weiss 	int nr = sattr->index;
2694c3963bc0SZev Weiss 	unsigned long val;
2695c3963bc0SZev Weiss 	int err, src;
2696c3963bc0SZev Weiss 	u16 reg;
2697c3963bc0SZev Weiss 
2698c3963bc0SZev Weiss 	if (IS_ERR(data))
2699c3963bc0SZev Weiss 		return PTR_ERR(data);
2700c3963bc0SZev Weiss 
2701c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2702c3963bc0SZev Weiss 	if (err < 0)
2703c3963bc0SZev Weiss 		return err;
2704c3963bc0SZev Weiss 	if (val == 0 || val > NUM_TEMP)
2705c3963bc0SZev Weiss 		return -EINVAL;
2706c3963bc0SZev Weiss 	if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
2707c3963bc0SZev Weiss 		return -EINVAL;
2708c3963bc0SZev Weiss 
2709c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2710c3963bc0SZev Weiss 	src = data->temp_src[val - 1];
2711c3963bc0SZev Weiss 	data->pwm_temp_sel[nr] = src;
2712c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_TEMP_SEL[nr], &reg);
2713c3963bc0SZev Weiss 	if (err)
2714c3963bc0SZev Weiss 		goto out;
2715c3963bc0SZev Weiss 	reg &= 0xe0;
2716c3963bc0SZev Weiss 	reg |= src;
2717c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2718c3963bc0SZev Weiss out:
2719c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2720c3963bc0SZev Weiss 
2721c3963bc0SZev Weiss 	return err ? : count;
2722c3963bc0SZev Weiss }
2723c3963bc0SZev Weiss 
2724c3963bc0SZev Weiss static ssize_t
2725c3963bc0SZev Weiss show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2726c3963bc0SZev Weiss 			 char *buf)
2727c3963bc0SZev Weiss {
2728c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2729c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2730c3963bc0SZev Weiss 	int index = sattr->index;
2731c3963bc0SZev Weiss 
2732c3963bc0SZev Weiss 	if (IS_ERR(data))
2733c3963bc0SZev Weiss 		return PTR_ERR(data);
2734c3963bc0SZev Weiss 
2735c3963bc0SZev Weiss 	return show_pwm_temp_sel_common(data, buf,
2736c3963bc0SZev Weiss 					data->pwm_weight_temp_sel[index]);
2737c3963bc0SZev Weiss }
2738c3963bc0SZev Weiss 
2739c3963bc0SZev Weiss static ssize_t
2740c3963bc0SZev Weiss store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2741c3963bc0SZev Weiss 			  const char *buf, size_t count)
2742c3963bc0SZev Weiss {
2743c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2744c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2745c3963bc0SZev Weiss 	int nr = sattr->index;
2746c3963bc0SZev Weiss 	unsigned long val;
2747c3963bc0SZev Weiss 	int err, src;
2748c3963bc0SZev Weiss 	u16 reg;
2749c3963bc0SZev Weiss 
2750c3963bc0SZev Weiss 	if (IS_ERR(data))
2751c3963bc0SZev Weiss 		return PTR_ERR(data);
2752c3963bc0SZev Weiss 
2753c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2754c3963bc0SZev Weiss 	if (err < 0)
2755c3963bc0SZev Weiss 		return err;
2756c3963bc0SZev Weiss 	if (val > NUM_TEMP)
2757c3963bc0SZev Weiss 		return -EINVAL;
2758c3963bc0SZev Weiss 	val = array_index_nospec(val, NUM_TEMP + 1);
2759c3963bc0SZev Weiss 	if (val && (!(data->have_temp & BIT(val - 1)) ||
2760c3963bc0SZev Weiss 		    !data->temp_src[val - 1]))
2761c3963bc0SZev Weiss 		return -EINVAL;
2762c3963bc0SZev Weiss 
2763c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2764c3963bc0SZev Weiss 	if (val) {
2765c3963bc0SZev Weiss 		src = data->temp_src[val - 1];
2766c3963bc0SZev Weiss 		data->pwm_weight_temp_sel[nr] = src;
2767c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr], &reg);
2768c3963bc0SZev Weiss 		if (err)
2769c3963bc0SZev Weiss 			goto out;
2770c3963bc0SZev Weiss 		reg &= 0xe0;
2771c3963bc0SZev Weiss 		reg |= (src | 0x80);
2772c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2773c3963bc0SZev Weiss 	} else {
2774c3963bc0SZev Weiss 		data->pwm_weight_temp_sel[nr] = 0;
2775c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr], &reg);
2776c3963bc0SZev Weiss 		if (err)
2777c3963bc0SZev Weiss 			goto out;
2778c3963bc0SZev Weiss 		reg &= 0x7f;
2779c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2780c3963bc0SZev Weiss 	}
2781c3963bc0SZev Weiss out:
2782c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2783c3963bc0SZev Weiss 
2784c3963bc0SZev Weiss 	return err ? : count;
2785c3963bc0SZev Weiss }
2786c3963bc0SZev Weiss 
2787c3963bc0SZev Weiss static ssize_t
2788c3963bc0SZev Weiss show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2789c3963bc0SZev Weiss {
2790c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2791c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2792c3963bc0SZev Weiss 
2793c3963bc0SZev Weiss 	if (IS_ERR(data))
2794c3963bc0SZev Weiss 		return PTR_ERR(data);
2795c3963bc0SZev Weiss 
2796c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2797c3963bc0SZev Weiss }
2798c3963bc0SZev Weiss 
2799c3963bc0SZev Weiss static ssize_t
2800c3963bc0SZev Weiss store_target_temp(struct device *dev, struct device_attribute *attr,
2801c3963bc0SZev Weiss 		  const char *buf, size_t count)
2802c3963bc0SZev Weiss {
2803c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2804c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2805c3963bc0SZev Weiss 	int nr = sattr->index;
2806c3963bc0SZev Weiss 	unsigned long val;
2807c3963bc0SZev Weiss 	int err;
2808c3963bc0SZev Weiss 
2809c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2810c3963bc0SZev Weiss 	if (err < 0)
2811c3963bc0SZev Weiss 		return err;
2812c3963bc0SZev Weiss 
2813c3963bc0SZev Weiss 	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2814c3963bc0SZev Weiss 			data->target_temp_mask);
2815c3963bc0SZev Weiss 
2816c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2817c3963bc0SZev Weiss 	data->target_temp[nr] = val;
2818c3963bc0SZev Weiss 	err = pwm_update_registers(data, nr);
2819c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2820c3963bc0SZev Weiss 	return err ? : count;
2821c3963bc0SZev Weiss }
2822c3963bc0SZev Weiss 
2823c3963bc0SZev Weiss static ssize_t
2824c3963bc0SZev Weiss show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2825c3963bc0SZev Weiss {
2826c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2827c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2828c3963bc0SZev Weiss 	int nr = sattr->index;
2829c3963bc0SZev Weiss 
2830c3963bc0SZev Weiss 	if (IS_ERR(data))
2831c3963bc0SZev Weiss 		return PTR_ERR(data);
2832c3963bc0SZev Weiss 
2833c3963bc0SZev Weiss 	return sprintf(buf, "%d\n",
2834c3963bc0SZev Weiss 		       fan_from_reg16(data->target_speed[nr],
2835c3963bc0SZev Weiss 				      data->fan_div[nr]));
2836c3963bc0SZev Weiss }
2837c3963bc0SZev Weiss 
2838c3963bc0SZev Weiss static ssize_t
2839c3963bc0SZev Weiss store_target_speed(struct device *dev, struct device_attribute *attr,
2840c3963bc0SZev Weiss 		   const char *buf, size_t count)
2841c3963bc0SZev Weiss {
2842c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2843c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2844c3963bc0SZev Weiss 	int nr = sattr->index;
2845c3963bc0SZev Weiss 	unsigned long val;
2846c3963bc0SZev Weiss 	int err;
2847c3963bc0SZev Weiss 	u16 speed;
2848c3963bc0SZev Weiss 
2849c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2850c3963bc0SZev Weiss 	if (err < 0)
2851c3963bc0SZev Weiss 		return err;
2852c3963bc0SZev Weiss 
2853c3963bc0SZev Weiss 	val = clamp_val(val, 0, 1350000U);
2854c3963bc0SZev Weiss 	speed = fan_to_reg(val, data->fan_div[nr]);
2855c3963bc0SZev Weiss 
2856c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2857c3963bc0SZev Weiss 	data->target_speed[nr] = speed;
2858c3963bc0SZev Weiss 	err = pwm_update_registers(data, nr);
2859c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2860c3963bc0SZev Weiss 	return err ? : count;
2861c3963bc0SZev Weiss }
2862c3963bc0SZev Weiss 
2863c3963bc0SZev Weiss static ssize_t
2864c3963bc0SZev Weiss show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2865c3963bc0SZev Weiss 		    char *buf)
2866c3963bc0SZev Weiss {
2867c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2868c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2869c3963bc0SZev Weiss 	int nr = sattr->nr;
2870c3963bc0SZev Weiss 	int index = sattr->index;
2871c3963bc0SZev Weiss 
2872c3963bc0SZev Weiss 	if (IS_ERR(data))
2873c3963bc0SZev Weiss 		return PTR_ERR(data);
2874c3963bc0SZev Weiss 
2875c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2876c3963bc0SZev Weiss }
2877c3963bc0SZev Weiss 
2878c3963bc0SZev Weiss static ssize_t
2879c3963bc0SZev Weiss store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2880c3963bc0SZev Weiss 		     const char *buf, size_t count)
2881c3963bc0SZev Weiss {
2882c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2883c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2884c3963bc0SZev Weiss 	int nr = sattr->nr;
2885c3963bc0SZev Weiss 	int index = sattr->index;
2886c3963bc0SZev Weiss 	unsigned long val;
2887c3963bc0SZev Weiss 	int err;
2888c3963bc0SZev Weiss 
2889c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2890c3963bc0SZev Weiss 	if (err < 0)
2891c3963bc0SZev Weiss 		return err;
2892c3963bc0SZev Weiss 
2893c3963bc0SZev Weiss 	/* Limit tolerance as needed */
2894c3963bc0SZev Weiss 	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2895c3963bc0SZev Weiss 
2896c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2897c3963bc0SZev Weiss 	data->temp_tolerance[index][nr] = val;
2898c3963bc0SZev Weiss 	if (index)
2899c3963bc0SZev Weiss 		err = pwm_update_registers(data, nr);
2900c3963bc0SZev Weiss 	else
2901c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_CRITICAL_TEMP_TOLERANCE[nr], val);
2902c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2903c3963bc0SZev Weiss 	return err ? : count;
2904c3963bc0SZev Weiss }
2905c3963bc0SZev Weiss 
2906c3963bc0SZev Weiss /*
2907c3963bc0SZev Weiss  * Fan speed tolerance is a tricky beast, since the associated register is
2908c3963bc0SZev Weiss  * a tick counter, but the value is reported and configured as rpm.
2909c3963bc0SZev Weiss  * Compute resulting low and high rpm values and report the difference.
2910c3963bc0SZev Weiss  * A fan speed tolerance only makes sense if a fan target speed has been
2911c3963bc0SZev Weiss  * configured, so only display values other than 0 if that is the case.
2912c3963bc0SZev Weiss  */
2913c3963bc0SZev Weiss static ssize_t
2914c3963bc0SZev Weiss show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2915c3963bc0SZev Weiss 		     char *buf)
2916c3963bc0SZev Weiss {
2917c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2918c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2919c3963bc0SZev Weiss 	int nr = sattr->index;
2920c3963bc0SZev Weiss 	int target, tolerance = 0;
2921c3963bc0SZev Weiss 
2922c3963bc0SZev Weiss 	if (IS_ERR(data))
2923c3963bc0SZev Weiss 		return PTR_ERR(data);
2924c3963bc0SZev Weiss 
2925c3963bc0SZev Weiss 	target = data->target_speed[nr];
2926c3963bc0SZev Weiss 
2927c3963bc0SZev Weiss 	if (target) {
2928c3963bc0SZev Weiss 		int low = target - data->target_speed_tolerance[nr];
2929c3963bc0SZev Weiss 		int high = target + data->target_speed_tolerance[nr];
2930c3963bc0SZev Weiss 
2931c3963bc0SZev Weiss 		if (low <= 0)
2932c3963bc0SZev Weiss 			low = 1;
2933c3963bc0SZev Weiss 		if (high > 0xffff)
2934c3963bc0SZev Weiss 			high = 0xffff;
2935c3963bc0SZev Weiss 		if (high < low)
2936c3963bc0SZev Weiss 			high = low;
2937c3963bc0SZev Weiss 
2938c3963bc0SZev Weiss 		tolerance = (fan_from_reg16(low, data->fan_div[nr])
2939c3963bc0SZev Weiss 			     - fan_from_reg16(high, data->fan_div[nr])) / 2;
2940c3963bc0SZev Weiss 	}
2941c3963bc0SZev Weiss 
2942c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", tolerance);
2943c3963bc0SZev Weiss }
2944c3963bc0SZev Weiss 
2945c3963bc0SZev Weiss static ssize_t
2946c3963bc0SZev Weiss store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2947c3963bc0SZev Weiss 		      const char *buf, size_t count)
2948c3963bc0SZev Weiss {
2949c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
2950c3963bc0SZev Weiss 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2951c3963bc0SZev Weiss 	int nr = sattr->index;
2952c3963bc0SZev Weiss 	unsigned long val;
2953c3963bc0SZev Weiss 	int err;
2954c3963bc0SZev Weiss 	int low, high;
2955c3963bc0SZev Weiss 
2956c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
2957c3963bc0SZev Weiss 	if (err < 0)
2958c3963bc0SZev Weiss 		return err;
2959c3963bc0SZev Weiss 
2960c3963bc0SZev Weiss 	high = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) + val;
2961c3963bc0SZev Weiss 	low = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) - val;
2962c3963bc0SZev Weiss 	if (low <= 0)
2963c3963bc0SZev Weiss 		low = 1;
2964c3963bc0SZev Weiss 	if (high < low)
2965c3963bc0SZev Weiss 		high = low;
2966c3963bc0SZev Weiss 
2967c3963bc0SZev Weiss 	val = (fan_to_reg(low, data->fan_div[nr]) -
2968c3963bc0SZev Weiss 	       fan_to_reg(high, data->fan_div[nr])) / 2;
2969c3963bc0SZev Weiss 
2970c3963bc0SZev Weiss 	/* Limit tolerance as needed */
2971c3963bc0SZev Weiss 	val = clamp_val(val, 0, data->speed_tolerance_limit);
2972c3963bc0SZev Weiss 
2973c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
2974c3963bc0SZev Weiss 	data->target_speed_tolerance[nr] = val;
2975c3963bc0SZev Weiss 	err = pwm_update_registers(data, nr);
2976c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
2977c3963bc0SZev Weiss 	return err ? : count;
2978c3963bc0SZev Weiss }
2979c3963bc0SZev Weiss 
2980c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm, "pwm%d", 0644, show_pwm, store_pwm, 0, 0);
2981c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", 0644, show_pwm_mode, store_pwm_mode, 0);
2982c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", 0644, show_pwm_enable, store_pwm_enable, 0);
2983c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", 0644, show_pwm_temp_sel, store_pwm_temp_sel, 0);
2984c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", 0644, show_target_temp, store_target_temp, 0);
2985c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_target, "fan%d_target", 0644, show_target_speed, store_target_speed, 0);
2986c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", 0644, show_speed_tolerance,
2987c3963bc0SZev Weiss 		store_speed_tolerance, 0);
2988c3963bc0SZev Weiss 
2989c3963bc0SZev Weiss /* Smart Fan registers */
2990c3963bc0SZev Weiss 
2991c3963bc0SZev Weiss static ssize_t
2992c3963bc0SZev Weiss show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2993c3963bc0SZev Weiss {
2994c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
2995c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2996c3963bc0SZev Weiss 	int nr = sattr->nr;
2997c3963bc0SZev Weiss 	int index = sattr->index;
2998c3963bc0SZev Weiss 
2999c3963bc0SZev Weiss 	if (IS_ERR(data))
3000c3963bc0SZev Weiss 		return PTR_ERR(data);
3001c3963bc0SZev Weiss 
3002c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
3003c3963bc0SZev Weiss }
3004c3963bc0SZev Weiss 
3005c3963bc0SZev Weiss static ssize_t
3006c3963bc0SZev Weiss store_weight_temp(struct device *dev, struct device_attribute *attr,
3007c3963bc0SZev Weiss 		  const char *buf, size_t count)
3008c3963bc0SZev Weiss {
3009c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
3010c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3011c3963bc0SZev Weiss 	int nr = sattr->nr;
3012c3963bc0SZev Weiss 	int index = sattr->index;
3013c3963bc0SZev Weiss 	unsigned long val;
3014c3963bc0SZev Weiss 	int err;
3015c3963bc0SZev Weiss 
3016c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
3017c3963bc0SZev Weiss 	if (err < 0)
3018c3963bc0SZev Weiss 		return err;
3019c3963bc0SZev Weiss 
3020c3963bc0SZev Weiss 	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
3021c3963bc0SZev Weiss 
3022c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
3023c3963bc0SZev Weiss 	data->weight_temp[index][nr] = val;
3024c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
3025c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
3026c3963bc0SZev Weiss 	return err ? : count;
3027c3963bc0SZev Weiss }
3028c3963bc0SZev Weiss 
3029c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", 0644,
3030c3963bc0SZev Weiss 		show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
3031c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
3032c3963bc0SZev Weiss 		  0644, show_weight_temp, store_weight_temp, 0, 0);
3033c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
3034c3963bc0SZev Weiss 		  0644, show_weight_temp, store_weight_temp, 0, 1);
3035c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
3036c3963bc0SZev Weiss 		  0644, show_weight_temp, store_weight_temp, 0, 2);
3037c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step", 0644, show_pwm, store_pwm, 0, 5);
3038c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base", 0644, show_pwm, store_pwm, 0, 6);
3039c3963bc0SZev Weiss 
3040c3963bc0SZev Weiss static ssize_t
3041c3963bc0SZev Weiss show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
3042c3963bc0SZev Weiss {
3043c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
3044c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3045c3963bc0SZev Weiss 	int nr = sattr->nr;
3046c3963bc0SZev Weiss 	int index = sattr->index;
3047c3963bc0SZev Weiss 
3048c3963bc0SZev Weiss 	if (IS_ERR(data))
3049c3963bc0SZev Weiss 		return PTR_ERR(data);
3050c3963bc0SZev Weiss 
3051c3963bc0SZev Weiss 	return sprintf(buf, "%d\n",
3052c3963bc0SZev Weiss 		       step_time_from_reg(data->fan_time[index][nr],
3053c3963bc0SZev Weiss 					  data->pwm_mode[nr]));
3054c3963bc0SZev Weiss }
3055c3963bc0SZev Weiss 
3056c3963bc0SZev Weiss static ssize_t
3057c3963bc0SZev Weiss store_fan_time(struct device *dev, struct device_attribute *attr,
3058c3963bc0SZev Weiss 	       const char *buf, size_t count)
3059c3963bc0SZev Weiss {
3060c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
3061c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3062c3963bc0SZev Weiss 	int nr = sattr->nr;
3063c3963bc0SZev Weiss 	int index = sattr->index;
3064c3963bc0SZev Weiss 	unsigned long val;
3065c3963bc0SZev Weiss 	int err;
3066c3963bc0SZev Weiss 
3067c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
3068c3963bc0SZev Weiss 	if (err < 0)
3069c3963bc0SZev Weiss 		return err;
3070c3963bc0SZev Weiss 
3071c3963bc0SZev Weiss 	val = step_time_to_reg(val, data->pwm_mode[nr]);
3072c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
3073c3963bc0SZev Weiss 	data->fan_time[index][nr] = val;
3074c3963bc0SZev Weiss 	err = nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
3075c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
3076c3963bc0SZev Weiss 	return err ? : count;
3077c3963bc0SZev Weiss }
3078c3963bc0SZev Weiss 
3079c3963bc0SZev Weiss static ssize_t
3080c3963bc0SZev Weiss show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3081c3963bc0SZev Weiss {
3082c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
3083c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3084c3963bc0SZev Weiss 
3085c3963bc0SZev Weiss 	if (IS_ERR(data))
3086c3963bc0SZev Weiss 		return PTR_ERR(data);
3087c3963bc0SZev Weiss 
3088c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3089c3963bc0SZev Weiss }
3090c3963bc0SZev Weiss 
3091c3963bc0SZev Weiss static ssize_t
3092c3963bc0SZev Weiss store_auto_pwm(struct device *dev, struct device_attribute *attr,
3093c3963bc0SZev Weiss 	       const char *buf, size_t count)
3094c3963bc0SZev Weiss {
3095c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
3096c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3097c3963bc0SZev Weiss 	int nr = sattr->nr;
3098c3963bc0SZev Weiss 	int point = sattr->index;
3099c3963bc0SZev Weiss 	unsigned long val;
3100c3963bc0SZev Weiss 	int err;
3101c3963bc0SZev Weiss 	u16 reg;
3102c3963bc0SZev Weiss 
3103c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
3104c3963bc0SZev Weiss 	if (err < 0)
3105c3963bc0SZev Weiss 		return err;
3106c3963bc0SZev Weiss 	if (val > 255)
3107c3963bc0SZev Weiss 		return -EINVAL;
3108c3963bc0SZev Weiss 
3109c3963bc0SZev Weiss 	if (point == data->auto_pwm_num) {
3110c3963bc0SZev Weiss 		if (data->kind != nct6775 && !val)
3111c3963bc0SZev Weiss 			return -EINVAL;
3112c3963bc0SZev Weiss 		if (data->kind != nct6779 && val)
3113c3963bc0SZev Weiss 			val = 0xff;
3114c3963bc0SZev Weiss 	}
3115c3963bc0SZev Weiss 
3116c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
3117c3963bc0SZev Weiss 	data->auto_pwm[nr][point] = val;
3118c3963bc0SZev Weiss 	if (point < data->auto_pwm_num) {
3119c3963bc0SZev Weiss 		err = nct6775_write_value(data, NCT6775_AUTO_PWM(data, nr, point),
3120c3963bc0SZev Weiss 					  data->auto_pwm[nr][point]);
3121c3963bc0SZev Weiss 	} else {
3122c3963bc0SZev Weiss 		switch (data->kind) {
3123c3963bc0SZev Weiss 		case nct6775:
3124c3963bc0SZev Weiss 			/* disable if needed (pwm == 0) */
3125c3963bc0SZev Weiss 			err = nct6775_read_value(data, NCT6775_REG_CRITICAL_ENAB[nr], &reg);
3126c3963bc0SZev Weiss 			if (err)
3127c3963bc0SZev Weiss 				break;
3128c3963bc0SZev Weiss 			if (val)
3129c3963bc0SZev Weiss 				reg |= 0x02;
3130c3963bc0SZev Weiss 			else
3131c3963bc0SZev Weiss 				reg &= ~0x02;
3132c3963bc0SZev Weiss 			err = nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr], reg);
3133c3963bc0SZev Weiss 			break;
3134c3963bc0SZev Weiss 		case nct6776:
3135c3963bc0SZev Weiss 			break; /* always enabled, nothing to do */
3136c3963bc0SZev Weiss 		case nct6106:
3137c3963bc0SZev Weiss 		case nct6116:
3138c3963bc0SZev Weiss 		case nct6779:
3139c3963bc0SZev Weiss 		case nct6791:
3140c3963bc0SZev Weiss 		case nct6792:
3141c3963bc0SZev Weiss 		case nct6793:
3142c3963bc0SZev Weiss 		case nct6795:
3143c3963bc0SZev Weiss 		case nct6796:
3144c3963bc0SZev Weiss 		case nct6797:
3145c3963bc0SZev Weiss 		case nct6798:
3146aee395bbSGuenter Roeck 		case nct6799:
3147c3963bc0SZev Weiss 			err = nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val);
3148c3963bc0SZev Weiss 			if (err)
3149c3963bc0SZev Weiss 				break;
3150c3963bc0SZev Weiss 			err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[nr], &reg);
3151c3963bc0SZev Weiss 			if (err)
3152c3963bc0SZev Weiss 				break;
3153c3963bc0SZev Weiss 			if (val == 255)
3154c3963bc0SZev Weiss 				reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
3155c3963bc0SZev Weiss 			else
3156c3963bc0SZev Weiss 				reg |= data->CRITICAL_PWM_ENABLE_MASK;
3157c3963bc0SZev Weiss 			err = nct6775_write_value(data, data->REG_CRITICAL_PWM_ENABLE[nr], reg);
3158c3963bc0SZev Weiss 			break;
3159c3963bc0SZev Weiss 		}
3160c3963bc0SZev Weiss 	}
3161c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
3162c3963bc0SZev Weiss 	return err ? : count;
3163c3963bc0SZev Weiss }
3164c3963bc0SZev Weiss 
3165c3963bc0SZev Weiss static ssize_t
3166c3963bc0SZev Weiss show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3167c3963bc0SZev Weiss {
3168c3963bc0SZev Weiss 	struct nct6775_data *data = nct6775_update_device(dev);
3169c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3170c3963bc0SZev Weiss 	int nr = sattr->nr;
3171c3963bc0SZev Weiss 	int point = sattr->index;
3172c3963bc0SZev Weiss 
3173c3963bc0SZev Weiss 	if (IS_ERR(data))
3174c3963bc0SZev Weiss 		return PTR_ERR(data);
3175c3963bc0SZev Weiss 
3176c3963bc0SZev Weiss 	/*
3177c3963bc0SZev Weiss 	 * We don't know for sure if the temperature is signed or unsigned.
3178c3963bc0SZev Weiss 	 * Assume it is unsigned.
3179c3963bc0SZev Weiss 	 */
3180c3963bc0SZev Weiss 	return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3181c3963bc0SZev Weiss }
3182c3963bc0SZev Weiss 
3183c3963bc0SZev Weiss static ssize_t
3184c3963bc0SZev Weiss store_auto_temp(struct device *dev, struct device_attribute *attr,
3185c3963bc0SZev Weiss 		const char *buf, size_t count)
3186c3963bc0SZev Weiss {
3187c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
3188c3963bc0SZev Weiss 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3189c3963bc0SZev Weiss 	int nr = sattr->nr;
3190c3963bc0SZev Weiss 	int point = sattr->index;
3191c3963bc0SZev Weiss 	unsigned long val;
3192c3963bc0SZev Weiss 	int err;
3193c3963bc0SZev Weiss 
3194c3963bc0SZev Weiss 	err = kstrtoul(buf, 10, &val);
3195c3963bc0SZev Weiss 	if (err)
3196c3963bc0SZev Weiss 		return err;
3197c3963bc0SZev Weiss 	if (val > 255000)
3198c3963bc0SZev Weiss 		return -EINVAL;
3199c3963bc0SZev Weiss 
3200c3963bc0SZev Weiss 	mutex_lock(&data->update_lock);
3201c3963bc0SZev Weiss 	data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3202c3963bc0SZev Weiss 	if (point < data->auto_pwm_num) {
3203c3963bc0SZev Weiss 		err = nct6775_write_value(data, NCT6775_AUTO_TEMP(data, nr, point),
3204c3963bc0SZev Weiss 					  data->auto_temp[nr][point]);
3205c3963bc0SZev Weiss 	} else {
3206c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3207c3963bc0SZev Weiss 					  data->auto_temp[nr][point]);
3208c3963bc0SZev Weiss 	}
3209c3963bc0SZev Weiss 	mutex_unlock(&data->update_lock);
3210c3963bc0SZev Weiss 	return err ? : count;
3211c3963bc0SZev Weiss }
3212c3963bc0SZev Weiss 
3213c3963bc0SZev Weiss static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3214c3963bc0SZev Weiss 				      struct attribute *attr, int index)
3215c3963bc0SZev Weiss {
3216c3963bc0SZev Weiss 	struct device *dev = kobj_to_dev(kobj);
3217c3963bc0SZev Weiss 	struct nct6775_data *data = dev_get_drvdata(dev);
3218c3963bc0SZev Weiss 	int pwm = index / 36;	/* pwm index */
3219c3963bc0SZev Weiss 	int nr = index % 36;	/* attribute index */
3220c3963bc0SZev Weiss 
3221c3963bc0SZev Weiss 	if (!(data->has_pwm & BIT(pwm)))
3222c3963bc0SZev Weiss 		return 0;
3223c3963bc0SZev Weiss 
3224c3963bc0SZev Weiss 	if ((nr >= 14 && nr <= 18) || nr == 21)   /* weight */
3225c3963bc0SZev Weiss 		if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3226c3963bc0SZev Weiss 			return 0;
3227c3963bc0SZev Weiss 	if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3228c3963bc0SZev Weiss 		return 0;
3229c3963bc0SZev Weiss 	if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3230c3963bc0SZev Weiss 		return 0;
3231c3963bc0SZev Weiss 	if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3232c3963bc0SZev Weiss 		return 0;
3233c3963bc0SZev Weiss 
3234c3963bc0SZev Weiss 	if (nr >= 22 && nr <= 35) {		/* auto point */
3235c3963bc0SZev Weiss 		int api = (nr - 22) / 2;	/* auto point index */
3236c3963bc0SZev Weiss 
3237c3963bc0SZev Weiss 		if (api > data->auto_pwm_num)
3238c3963bc0SZev Weiss 			return 0;
3239c3963bc0SZev Weiss 	}
3240c3963bc0SZev Weiss 	return nct6775_attr_mode(data, attr);
3241c3963bc0SZev Weiss }
3242c3963bc0SZev Weiss 
3243c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", 0644, show_fan_time, store_fan_time, 0, 0);
3244c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", 0644,
3245c3963bc0SZev Weiss 		  show_fan_time, store_fan_time, 0, 1);
3246c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", 0644,
3247c3963bc0SZev Weiss 		  show_fan_time, store_fan_time, 0, 2);
3248c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", 0644, show_pwm, store_pwm, 0, 1);
3249c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", 0644, show_pwm, store_pwm, 0, 2);
3250c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", 0644,
3251c3963bc0SZev Weiss 		  show_temp_tolerance, store_temp_tolerance, 0, 0);
3252c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3253c3963bc0SZev Weiss 		  0644, show_temp_tolerance, store_temp_tolerance, 0, 1);
3254c3963bc0SZev Weiss 
3255c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", 0644, show_pwm, store_pwm, 0, 3);
3256c3963bc0SZev Weiss 
3257c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", 0644, show_pwm, store_pwm, 0, 4);
3258c3963bc0SZev Weiss 
3259c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3260c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 0);
3261c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3262c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 0);
3263c3963bc0SZev Weiss 
3264c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3265c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 1);
3266c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3267c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 1);
3268c3963bc0SZev Weiss 
3269c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3270c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 2);
3271c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3272c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 2);
3273c3963bc0SZev Weiss 
3274c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3275c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 3);
3276c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3277c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 3);
3278c3963bc0SZev Weiss 
3279c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3280c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 4);
3281c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3282c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 4);
3283c3963bc0SZev Weiss 
3284c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3285c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 5);
3286c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3287c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 5);
3288c3963bc0SZev Weiss 
3289c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3290c3963bc0SZev Weiss 		  0644, show_auto_pwm, store_auto_pwm, 0, 6);
3291c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3292c3963bc0SZev Weiss 		  0644, show_auto_temp, store_auto_temp, 0, 6);
3293c3963bc0SZev Weiss 
3294c3963bc0SZev Weiss /*
3295c3963bc0SZev Weiss  * nct6775_pwm_is_visible uses the index into the following array
3296c3963bc0SZev Weiss  * to determine if attributes should be created or not.
3297c3963bc0SZev Weiss  * Any change in order or content must be matched.
3298c3963bc0SZev Weiss  */
3299c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3300c3963bc0SZev Weiss 	&sensor_dev_template_pwm,
3301c3963bc0SZev Weiss 	&sensor_dev_template_pwm_mode,
3302c3963bc0SZev Weiss 	&sensor_dev_template_pwm_enable,
3303c3963bc0SZev Weiss 	&sensor_dev_template_pwm_temp_sel,
3304c3963bc0SZev Weiss 	&sensor_dev_template_pwm_temp_tolerance,
3305c3963bc0SZev Weiss 	&sensor_dev_template_pwm_crit_temp_tolerance,
3306c3963bc0SZev Weiss 	&sensor_dev_template_pwm_target_temp,
3307c3963bc0SZev Weiss 	&sensor_dev_template_fan_target,
3308c3963bc0SZev Weiss 	&sensor_dev_template_fan_tolerance,
3309c3963bc0SZev Weiss 	&sensor_dev_template_pwm_stop_time,
3310c3963bc0SZev Weiss 	&sensor_dev_template_pwm_step_up_time,
3311c3963bc0SZev Weiss 	&sensor_dev_template_pwm_step_down_time,
3312c3963bc0SZev Weiss 	&sensor_dev_template_pwm_start,
3313c3963bc0SZev Weiss 	&sensor_dev_template_pwm_floor,
3314c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_temp_sel,	/* 14 */
3315c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_temp_step,
3316c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_temp_step_tol,
3317c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_temp_step_base,
3318c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_duty_step,	/* 18 */
3319c3963bc0SZev Weiss 	&sensor_dev_template_pwm_max,			/* 19 */
3320c3963bc0SZev Weiss 	&sensor_dev_template_pwm_step,			/* 20 */
3321c3963bc0SZev Weiss 	&sensor_dev_template_pwm_weight_duty_base,	/* 21 */
3322c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point1_pwm,	/* 22 */
3323c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point1_temp,
3324c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point2_pwm,
3325c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point2_temp,
3326c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point3_pwm,
3327c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point3_temp,
3328c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point4_pwm,
3329c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point4_temp,
3330c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point5_pwm,
3331c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point5_temp,
3332c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point6_pwm,
3333c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point6_temp,
3334c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point7_pwm,
3335c3963bc0SZev Weiss 	&sensor_dev_template_pwm_auto_point7_temp,	/* 35 */
3336c3963bc0SZev Weiss 
3337c3963bc0SZev Weiss 	NULL
3338c3963bc0SZev Weiss };
3339c3963bc0SZev Weiss 
3340c3963bc0SZev Weiss static const struct sensor_template_group nct6775_pwm_template_group = {
3341c3963bc0SZev Weiss 	.templates = nct6775_attributes_pwm_template,
3342c3963bc0SZev Weiss 	.is_visible = nct6775_pwm_is_visible,
3343c3963bc0SZev Weiss 	.base = 1,
3344c3963bc0SZev Weiss };
3345c3963bc0SZev Weiss 
3346c3963bc0SZev Weiss static inline int nct6775_init_device(struct nct6775_data *data)
3347c3963bc0SZev Weiss {
3348c3963bc0SZev Weiss 	int i, err;
3349c3963bc0SZev Weiss 	u16 tmp, diode;
3350c3963bc0SZev Weiss 
3351c3963bc0SZev Weiss 	/* Start monitoring if needed */
3352c3963bc0SZev Weiss 	if (data->REG_CONFIG) {
3353c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_CONFIG, &tmp);
3354c3963bc0SZev Weiss 		if (err)
3355c3963bc0SZev Weiss 			return err;
3356c3963bc0SZev Weiss 		if (!(tmp & 0x01)) {
3357c3963bc0SZev Weiss 			err = nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3358c3963bc0SZev Weiss 			if (err)
3359c3963bc0SZev Weiss 				return err;
3360c3963bc0SZev Weiss 		}
3361c3963bc0SZev Weiss 	}
3362c3963bc0SZev Weiss 
3363c3963bc0SZev Weiss 	/* Enable temperature sensors if needed */
3364c3963bc0SZev Weiss 	for (i = 0; i < NUM_TEMP; i++) {
3365c3963bc0SZev Weiss 		if (!(data->have_temp & BIT(i)))
3366c3963bc0SZev Weiss 			continue;
3367c3963bc0SZev Weiss 		if (!data->reg_temp_config[i])
3368c3963bc0SZev Weiss 			continue;
3369c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->reg_temp_config[i], &tmp);
3370c3963bc0SZev Weiss 		if (err)
3371c3963bc0SZev Weiss 			return err;
3372c3963bc0SZev Weiss 		if (tmp & 0x01) {
3373c3963bc0SZev Weiss 			err = nct6775_write_value(data, data->reg_temp_config[i], tmp & 0xfe);
3374c3963bc0SZev Weiss 			if (err)
3375c3963bc0SZev Weiss 				return err;
3376c3963bc0SZev Weiss 		}
3377c3963bc0SZev Weiss 	}
3378c3963bc0SZev Weiss 
3379c3963bc0SZev Weiss 	/* Enable VBAT monitoring if needed */
3380c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_VBAT, &tmp);
3381c3963bc0SZev Weiss 	if (err)
3382c3963bc0SZev Weiss 		return err;
3383c3963bc0SZev Weiss 	if (!(tmp & 0x01)) {
3384c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
3385c3963bc0SZev Weiss 		if (err)
3386c3963bc0SZev Weiss 			return err;
3387c3963bc0SZev Weiss 	}
3388c3963bc0SZev Weiss 
3389c3963bc0SZev Weiss 	err = nct6775_read_value(data, data->REG_DIODE, &diode);
3390c3963bc0SZev Weiss 	if (err)
3391c3963bc0SZev Weiss 		return err;
3392c3963bc0SZev Weiss 
3393c3963bc0SZev Weiss 	for (i = 0; i < data->temp_fixed_num; i++) {
3394c3963bc0SZev Weiss 		if (!(data->have_temp_fixed & BIT(i)))
3395c3963bc0SZev Weiss 			continue;
3396c3963bc0SZev Weiss 		if ((tmp & (data->DIODE_MASK << i)))	/* diode */
3397c3963bc0SZev Weiss 			data->temp_type[i]
3398c3963bc0SZev Weiss 			  = 3 - ((diode >> i) & data->DIODE_MASK);
3399c3963bc0SZev Weiss 		else				/* thermistor */
3400c3963bc0SZev Weiss 			data->temp_type[i] = 4;
3401c3963bc0SZev Weiss 	}
3402c3963bc0SZev Weiss 
3403c3963bc0SZev Weiss 	return 0;
3404c3963bc0SZev Weiss }
3405c3963bc0SZev Weiss 
3406c3963bc0SZev Weiss static int add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3407c3963bc0SZev Weiss 			    int *available, int *mask)
3408c3963bc0SZev Weiss {
3409c3963bc0SZev Weiss 	int i, err;
3410c3963bc0SZev Weiss 	u16 src;
3411c3963bc0SZev Weiss 
3412c3963bc0SZev Weiss 	for (i = 0; i < data->pwm_num && *available; i++) {
3413c3963bc0SZev Weiss 		int index;
3414c3963bc0SZev Weiss 
3415c3963bc0SZev Weiss 		if (!regp[i])
3416c3963bc0SZev Weiss 			continue;
3417c3963bc0SZev Weiss 		err = nct6775_read_value(data, regp[i], &src);
3418c3963bc0SZev Weiss 		if (err)
3419c3963bc0SZev Weiss 			return err;
3420c3963bc0SZev Weiss 		src &= 0x1f;
3421c3963bc0SZev Weiss 		if (!src || (*mask & BIT(src)))
3422c3963bc0SZev Weiss 			continue;
3423c3963bc0SZev Weiss 		if (!(data->temp_mask & BIT(src)))
3424c3963bc0SZev Weiss 			continue;
3425c3963bc0SZev Weiss 
3426c3963bc0SZev Weiss 		index = __ffs(*available);
3427c3963bc0SZev Weiss 		err = nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3428c3963bc0SZev Weiss 		if (err)
3429c3963bc0SZev Weiss 			return err;
3430c3963bc0SZev Weiss 		*available &= ~BIT(index);
3431c3963bc0SZev Weiss 		*mask |= BIT(src);
3432c3963bc0SZev Weiss 	}
3433c3963bc0SZev Weiss 
3434c3963bc0SZev Weiss 	return 0;
3435c3963bc0SZev Weiss }
3436c3963bc0SZev Weiss 
3437c3963bc0SZev Weiss int nct6775_probe(struct device *dev, struct nct6775_data *data,
3438c3963bc0SZev Weiss 		  const struct regmap_config *regmapcfg)
3439c3963bc0SZev Weiss {
3440c3963bc0SZev Weiss 	int i, s, err = 0;
3441c3963bc0SZev Weiss 	int mask, available;
3442c3963bc0SZev Weiss 	u16 src;
3443c3963bc0SZev Weiss 	const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
3444c3963bc0SZev Weiss 	const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
3445c3963bc0SZev Weiss 	const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
3446c3963bc0SZev Weiss 	int num_reg_temp, num_reg_temp_mon, num_reg_tsi_temp;
3447c3963bc0SZev Weiss 	struct device *hwmon_dev;
3448c3963bc0SZev Weiss 	struct sensor_template_group tsi_temp_tg;
3449c3963bc0SZev Weiss 
3450c3963bc0SZev Weiss 	data->regmap = devm_regmap_init(dev, NULL, data, regmapcfg);
3451c3963bc0SZev Weiss 	if (IS_ERR(data->regmap))
3452c3963bc0SZev Weiss 		return PTR_ERR(data->regmap);
3453c3963bc0SZev Weiss 
3454c3963bc0SZev Weiss 	mutex_init(&data->update_lock);
3455c3963bc0SZev Weiss 	data->name = nct6775_device_names[data->kind];
3456c3963bc0SZev Weiss 	data->bank = 0xff;		/* Force initial bank selection */
345713558a2eSAhmad Khalifa 	data->scale_in = scale_in;
3458c3963bc0SZev Weiss 
3459c3963bc0SZev Weiss 	switch (data->kind) {
3460c3963bc0SZev Weiss 	case nct6106:
3461c3963bc0SZev Weiss 		data->in_num = 9;
3462c3963bc0SZev Weiss 		data->pwm_num = 3;
3463c3963bc0SZev Weiss 		data->auto_pwm_num = 4;
3464c3963bc0SZev Weiss 		data->temp_fixed_num = 3;
3465c3963bc0SZev Weiss 		data->num_temp_alarms = 6;
3466c3963bc0SZev Weiss 		data->num_temp_beeps = 6;
3467c3963bc0SZev Weiss 
3468c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg13;
3469c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg13;
3470c3963bc0SZev Weiss 
3471c3963bc0SZev Weiss 		data->temp_label = nct6776_temp_label;
3472c3963bc0SZev Weiss 		data->temp_mask = NCT6776_TEMP_MASK;
3473c3963bc0SZev Weiss 		data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
3474c3963bc0SZev Weiss 
3475c3963bc0SZev Weiss 		data->REG_VBAT = NCT6106_REG_VBAT;
3476c3963bc0SZev Weiss 		data->REG_DIODE = NCT6106_REG_DIODE;
3477c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6106_DIODE_MASK;
3478c3963bc0SZev Weiss 		data->REG_VIN = NCT6106_REG_IN;
3479c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3480c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3481c3963bc0SZev Weiss 		data->REG_TARGET = NCT6106_REG_TARGET;
3482c3963bc0SZev Weiss 		data->REG_FAN = NCT6106_REG_FAN;
3483c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3484c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3485c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3486c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3487c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3488c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3489c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3490c3963bc0SZev Weiss 		data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
3491c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6116_REG_PWM;
3492c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3493c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3494c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3495c3963bc0SZev Weiss 		data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3496c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3497c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3498c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3499c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3500c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3501c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3502c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3503c3963bc0SZev Weiss 		  = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3504c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3505c3963bc0SZev Weiss 		data->CRITICAL_PWM_ENABLE_MASK
3506c3963bc0SZev Weiss 		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3507c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3508c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3509c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3510c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
3511c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3512c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3513c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3514c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3515c3963bc0SZev Weiss 		data->REG_ALARM = NCT6106_REG_ALARM;
3516c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6106_ALARM_BITS;
3517c3963bc0SZev Weiss 		data->REG_BEEP = NCT6106_REG_BEEP;
3518c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6106_BEEP_BITS;
3519c3963bc0SZev Weiss 		data->REG_TSI_TEMP = NCT6106_REG_TSI_TEMP;
3520c3963bc0SZev Weiss 
3521c3963bc0SZev Weiss 		reg_temp = NCT6106_REG_TEMP;
3522c3963bc0SZev Weiss 		reg_temp_mon = NCT6106_REG_TEMP_MON;
3523c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
3524c3963bc0SZev Weiss 		num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
3525c3963bc0SZev Weiss 		num_reg_tsi_temp = ARRAY_SIZE(NCT6106_REG_TSI_TEMP);
3526c3963bc0SZev Weiss 		reg_temp_over = NCT6106_REG_TEMP_OVER;
3527c3963bc0SZev Weiss 		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3528c3963bc0SZev Weiss 		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3529c3963bc0SZev Weiss 		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3530c3963bc0SZev Weiss 		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
3531c3963bc0SZev Weiss 		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3532c3963bc0SZev Weiss 		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
3533c3963bc0SZev Weiss 
3534c3963bc0SZev Weiss 		break;
3535c3963bc0SZev Weiss 	case nct6116:
3536c3963bc0SZev Weiss 		data->in_num = 9;
3537c3963bc0SZev Weiss 		data->pwm_num = 3;
3538c3963bc0SZev Weiss 		data->auto_pwm_num = 4;
3539c3963bc0SZev Weiss 		data->temp_fixed_num = 3;
3540c3963bc0SZev Weiss 		data->num_temp_alarms = 3;
3541c3963bc0SZev Weiss 		data->num_temp_beeps = 3;
3542c3963bc0SZev Weiss 
3543c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg13;
3544c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg13;
3545c3963bc0SZev Weiss 
3546c3963bc0SZev Weiss 		data->temp_label = nct6776_temp_label;
3547c3963bc0SZev Weiss 		data->temp_mask = NCT6776_TEMP_MASK;
3548c3963bc0SZev Weiss 		data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
3549c3963bc0SZev Weiss 
3550c3963bc0SZev Weiss 		data->REG_VBAT = NCT6106_REG_VBAT;
3551c3963bc0SZev Weiss 		data->REG_DIODE = NCT6106_REG_DIODE;
3552c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6106_DIODE_MASK;
3553c3963bc0SZev Weiss 		data->REG_VIN = NCT6106_REG_IN;
3554c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3555c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3556c3963bc0SZev Weiss 		data->REG_TARGET = NCT6116_REG_TARGET;
3557c3963bc0SZev Weiss 		data->REG_FAN = NCT6116_REG_FAN;
3558c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
3559c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
3560c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
3561c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
3562c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
3563c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
3564c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
3565c3963bc0SZev Weiss 		data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
3566c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6116_REG_PWM;
3567c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
3568c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
3569c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3570c3963bc0SZev Weiss 		data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3571c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3572c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3573c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3574c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
3575c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
3576c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
3577c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3578c3963bc0SZev Weiss 		  = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
3579c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
3580c3963bc0SZev Weiss 		data->CRITICAL_PWM_ENABLE_MASK
3581c3963bc0SZev Weiss 		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3582c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
3583c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3584c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
3585c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
3586c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3587c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3588c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3589c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3590c3963bc0SZev Weiss 		data->REG_ALARM = NCT6106_REG_ALARM;
3591c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6116_ALARM_BITS;
3592c3963bc0SZev Weiss 		data->REG_BEEP = NCT6106_REG_BEEP;
3593c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6116_BEEP_BITS;
3594c3963bc0SZev Weiss 		data->REG_TSI_TEMP = NCT6116_REG_TSI_TEMP;
3595c3963bc0SZev Weiss 
3596c3963bc0SZev Weiss 		reg_temp = NCT6106_REG_TEMP;
3597c3963bc0SZev Weiss 		reg_temp_mon = NCT6106_REG_TEMP_MON;
3598c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
3599c3963bc0SZev Weiss 		num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
3600c3963bc0SZev Weiss 		num_reg_tsi_temp = ARRAY_SIZE(NCT6116_REG_TSI_TEMP);
3601c3963bc0SZev Weiss 		reg_temp_over = NCT6106_REG_TEMP_OVER;
3602c3963bc0SZev Weiss 		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3603c3963bc0SZev Weiss 		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3604c3963bc0SZev Weiss 		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3605c3963bc0SZev Weiss 		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
3606c3963bc0SZev Weiss 		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3607c3963bc0SZev Weiss 		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
3608c3963bc0SZev Weiss 
3609c3963bc0SZev Weiss 		break;
3610c3963bc0SZev Weiss 	case nct6775:
3611c3963bc0SZev Weiss 		data->in_num = 9;
3612c3963bc0SZev Weiss 		data->pwm_num = 3;
3613c3963bc0SZev Weiss 		data->auto_pwm_num = 6;
3614c3963bc0SZev Weiss 		data->has_fan_div = true;
3615c3963bc0SZev Weiss 		data->temp_fixed_num = 3;
3616c3963bc0SZev Weiss 		data->num_temp_alarms = 3;
3617c3963bc0SZev Weiss 		data->num_temp_beeps = 3;
3618c3963bc0SZev Weiss 
3619c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6775_ALARM_BITS;
3620c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6775_BEEP_BITS;
3621c3963bc0SZev Weiss 
3622c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg16;
3623c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg8;
3624c3963bc0SZev Weiss 		data->target_temp_mask = 0x7f;
3625c3963bc0SZev Weiss 		data->tolerance_mask = 0x0f;
3626c3963bc0SZev Weiss 		data->speed_tolerance_limit = 15;
3627c3963bc0SZev Weiss 
3628c3963bc0SZev Weiss 		data->temp_label = nct6775_temp_label;
3629c3963bc0SZev Weiss 		data->temp_mask = NCT6775_TEMP_MASK;
3630c3963bc0SZev Weiss 		data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
3631c3963bc0SZev Weiss 
3632c3963bc0SZev Weiss 		data->REG_CONFIG = NCT6775_REG_CONFIG;
3633c3963bc0SZev Weiss 		data->REG_VBAT = NCT6775_REG_VBAT;
3634c3963bc0SZev Weiss 		data->REG_DIODE = NCT6775_REG_DIODE;
3635c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6775_DIODE_MASK;
3636c3963bc0SZev Weiss 		data->REG_VIN = NCT6775_REG_IN;
3637c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3638c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3639c3963bc0SZev Weiss 		data->REG_TARGET = NCT6775_REG_TARGET;
3640c3963bc0SZev Weiss 		data->REG_FAN = NCT6775_REG_FAN;
3641c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3642c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
3643c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
3644c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3645c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3646c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3647c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3648c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6775_REG_PWM;
3649c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3650c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3651c3963bc0SZev Weiss 		data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3652c3963bc0SZev Weiss 		data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
3653c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3654c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3655c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3656c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
3657c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3658c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3659c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3660c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3661c3963bc0SZev Weiss 		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3662c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3663c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3664c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
3665c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3666c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3667c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3668c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
3669c3963bc0SZev Weiss 		data->REG_ALARM = NCT6775_REG_ALARM;
3670c3963bc0SZev Weiss 		data->REG_BEEP = NCT6775_REG_BEEP;
3671c3963bc0SZev Weiss 		data->REG_TSI_TEMP = NCT6775_REG_TSI_TEMP;
3672c3963bc0SZev Weiss 
3673c3963bc0SZev Weiss 		reg_temp = NCT6775_REG_TEMP;
3674c3963bc0SZev Weiss 		reg_temp_mon = NCT6775_REG_TEMP_MON;
3675c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
3676c3963bc0SZev Weiss 		num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
3677c3963bc0SZev Weiss 		num_reg_tsi_temp = ARRAY_SIZE(NCT6775_REG_TSI_TEMP);
3678c3963bc0SZev Weiss 		reg_temp_over = NCT6775_REG_TEMP_OVER;
3679c3963bc0SZev Weiss 		reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3680c3963bc0SZev Weiss 		reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3681c3963bc0SZev Weiss 		reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3682c3963bc0SZev Weiss 		reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3683c3963bc0SZev Weiss 
3684c3963bc0SZev Weiss 		break;
3685c3963bc0SZev Weiss 	case nct6776:
3686c3963bc0SZev Weiss 		data->in_num = 9;
3687c3963bc0SZev Weiss 		data->pwm_num = 3;
3688c3963bc0SZev Weiss 		data->auto_pwm_num = 4;
3689c3963bc0SZev Weiss 		data->has_fan_div = false;
3690c3963bc0SZev Weiss 		data->temp_fixed_num = 3;
3691c3963bc0SZev Weiss 		data->num_temp_alarms = 3;
3692c3963bc0SZev Weiss 		data->num_temp_beeps = 6;
3693c3963bc0SZev Weiss 
3694c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6776_ALARM_BITS;
3695c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6776_BEEP_BITS;
3696c3963bc0SZev Weiss 
3697c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg13;
3698c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg13;
3699c3963bc0SZev Weiss 		data->target_temp_mask = 0xff;
3700c3963bc0SZev Weiss 		data->tolerance_mask = 0x07;
3701c3963bc0SZev Weiss 		data->speed_tolerance_limit = 63;
3702c3963bc0SZev Weiss 
3703c3963bc0SZev Weiss 		data->temp_label = nct6776_temp_label;
3704c3963bc0SZev Weiss 		data->temp_mask = NCT6776_TEMP_MASK;
3705c3963bc0SZev Weiss 		data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
3706c3963bc0SZev Weiss 
3707c3963bc0SZev Weiss 		data->REG_CONFIG = NCT6775_REG_CONFIG;
3708c3963bc0SZev Weiss 		data->REG_VBAT = NCT6775_REG_VBAT;
3709c3963bc0SZev Weiss 		data->REG_DIODE = NCT6775_REG_DIODE;
3710c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6775_DIODE_MASK;
3711c3963bc0SZev Weiss 		data->REG_VIN = NCT6775_REG_IN;
3712c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3713c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3714c3963bc0SZev Weiss 		data->REG_TARGET = NCT6775_REG_TARGET;
3715c3963bc0SZev Weiss 		data->REG_FAN = NCT6775_REG_FAN;
3716c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3717c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3718c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
3719c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3720c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3721c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3722c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
3723c3963bc0SZev Weiss 		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3724c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6775_REG_PWM;
3725c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3726c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3727c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3728c3963bc0SZev Weiss 		data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
3729c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3730c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3731c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3732c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3733c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3734c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3735c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3736c3963bc0SZev Weiss 		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3737c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3738c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3739c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
3740c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3741c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3742c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3743c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
3744c3963bc0SZev Weiss 		data->REG_ALARM = NCT6775_REG_ALARM;
3745c3963bc0SZev Weiss 		data->REG_BEEP = NCT6776_REG_BEEP;
3746c3963bc0SZev Weiss 		data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP;
3747c3963bc0SZev Weiss 
3748c3963bc0SZev Weiss 		reg_temp = NCT6775_REG_TEMP;
3749c3963bc0SZev Weiss 		reg_temp_mon = NCT6775_REG_TEMP_MON;
3750c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
3751c3963bc0SZev Weiss 		num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
3752c3963bc0SZev Weiss 		num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP);
3753c3963bc0SZev Weiss 		reg_temp_over = NCT6775_REG_TEMP_OVER;
3754c3963bc0SZev Weiss 		reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3755c3963bc0SZev Weiss 		reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3756c3963bc0SZev Weiss 		reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3757c3963bc0SZev Weiss 		reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3758c3963bc0SZev Weiss 
3759c3963bc0SZev Weiss 		break;
3760c3963bc0SZev Weiss 	case nct6779:
3761c3963bc0SZev Weiss 		data->in_num = 15;
3762c3963bc0SZev Weiss 		data->pwm_num = 5;
3763c3963bc0SZev Weiss 		data->auto_pwm_num = 4;
3764c3963bc0SZev Weiss 		data->has_fan_div = false;
3765c3963bc0SZev Weiss 		data->temp_fixed_num = 6;
3766c3963bc0SZev Weiss 		data->num_temp_alarms = 2;
3767c3963bc0SZev Weiss 		data->num_temp_beeps = 2;
3768c3963bc0SZev Weiss 
3769c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6779_ALARM_BITS;
3770c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6779_BEEP_BITS;
3771c3963bc0SZev Weiss 
3772c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg_rpm;
3773c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg13;
3774c3963bc0SZev Weiss 		data->target_temp_mask = 0xff;
3775c3963bc0SZev Weiss 		data->tolerance_mask = 0x07;
3776c3963bc0SZev Weiss 		data->speed_tolerance_limit = 63;
3777c3963bc0SZev Weiss 
3778c3963bc0SZev Weiss 		data->temp_label = nct6779_temp_label;
3779c3963bc0SZev Weiss 		data->temp_mask = NCT6779_TEMP_MASK;
3780c3963bc0SZev Weiss 		data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
3781c3963bc0SZev Weiss 
3782c3963bc0SZev Weiss 		data->REG_CONFIG = NCT6775_REG_CONFIG;
3783c3963bc0SZev Weiss 		data->REG_VBAT = NCT6775_REG_VBAT;
3784c3963bc0SZev Weiss 		data->REG_DIODE = NCT6775_REG_DIODE;
3785c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6775_DIODE_MASK;
3786c3963bc0SZev Weiss 		data->REG_VIN = NCT6779_REG_IN;
3787c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3788c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3789c3963bc0SZev Weiss 		data->REG_TARGET = NCT6775_REG_TARGET;
3790c3963bc0SZev Weiss 		data->REG_FAN = NCT6779_REG_FAN;
3791c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3792c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3793c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3794c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3795c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3796c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3797c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
3798c3963bc0SZev Weiss 		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3799c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6775_REG_PWM;
3800c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3801c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3802c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3803c3963bc0SZev Weiss 		data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
3804c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3805c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3806c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3807c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3808c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3809c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3810c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3811c3963bc0SZev Weiss 		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3812c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3813c3963bc0SZev Weiss 		data->CRITICAL_PWM_ENABLE_MASK
3814c3963bc0SZev Weiss 		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3815c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3816c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3817c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3818c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
3819c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3820c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3821c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3822c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
3823c3963bc0SZev Weiss 		data->REG_ALARM = NCT6779_REG_ALARM;
3824c3963bc0SZev Weiss 		data->REG_BEEP = NCT6776_REG_BEEP;
3825c3963bc0SZev Weiss 		data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP;
3826c3963bc0SZev Weiss 
3827c3963bc0SZev Weiss 		reg_temp = NCT6779_REG_TEMP;
3828c3963bc0SZev Weiss 		reg_temp_mon = NCT6779_REG_TEMP_MON;
3829c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
3830c3963bc0SZev Weiss 		num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3831c3963bc0SZev Weiss 		num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP);
3832c3963bc0SZev Weiss 		reg_temp_over = NCT6779_REG_TEMP_OVER;
3833c3963bc0SZev Weiss 		reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3834c3963bc0SZev Weiss 		reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3835c3963bc0SZev Weiss 		reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3836c3963bc0SZev Weiss 		reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3837c3963bc0SZev Weiss 
3838c3963bc0SZev Weiss 		break;
3839c3963bc0SZev Weiss 	case nct6791:
3840c3963bc0SZev Weiss 	case nct6792:
3841c3963bc0SZev Weiss 	case nct6793:
3842c3963bc0SZev Weiss 	case nct6795:
3843c3963bc0SZev Weiss 	case nct6796:
3844c3963bc0SZev Weiss 	case nct6797:
3845c3963bc0SZev Weiss 	case nct6798:
3846aee395bbSGuenter Roeck 	case nct6799:
3847c3963bc0SZev Weiss 		data->in_num = 15;
3848c3963bc0SZev Weiss 		data->pwm_num = (data->kind == nct6796 ||
3849c3963bc0SZev Weiss 				 data->kind == nct6797 ||
3850aee395bbSGuenter Roeck 				 data->kind == nct6798 ||
3851aee395bbSGuenter Roeck 				 data->kind == nct6799) ? 7 : 6;
3852c3963bc0SZev Weiss 		data->auto_pwm_num = 4;
3853c3963bc0SZev Weiss 		data->has_fan_div = false;
3854c3963bc0SZev Weiss 		data->temp_fixed_num = 6;
3855c3963bc0SZev Weiss 		data->num_temp_alarms = 2;
3856c3963bc0SZev Weiss 		data->num_temp_beeps = 2;
3857c3963bc0SZev Weiss 
3858c3963bc0SZev Weiss 		data->ALARM_BITS = NCT6791_ALARM_BITS;
3859c3963bc0SZev Weiss 		data->BEEP_BITS = NCT6779_BEEP_BITS;
3860c3963bc0SZev Weiss 
3861c3963bc0SZev Weiss 		data->fan_from_reg = fan_from_reg_rpm;
3862c3963bc0SZev Weiss 		data->fan_from_reg_min = fan_from_reg13;
3863c3963bc0SZev Weiss 		data->target_temp_mask = 0xff;
3864c3963bc0SZev Weiss 		data->tolerance_mask = 0x07;
3865c3963bc0SZev Weiss 		data->speed_tolerance_limit = 63;
3866c3963bc0SZev Weiss 
3867c3963bc0SZev Weiss 		switch (data->kind) {
3868c3963bc0SZev Weiss 		default:
3869c3963bc0SZev Weiss 		case nct6791:
3870c3963bc0SZev Weiss 			data->temp_label = nct6779_temp_label;
3871c3963bc0SZev Weiss 			data->temp_mask = NCT6791_TEMP_MASK;
3872c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
3873c3963bc0SZev Weiss 			break;
3874c3963bc0SZev Weiss 		case nct6792:
3875c3963bc0SZev Weiss 			data->temp_label = nct6792_temp_label;
3876c3963bc0SZev Weiss 			data->temp_mask = NCT6792_TEMP_MASK;
3877c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
3878c3963bc0SZev Weiss 			break;
3879c3963bc0SZev Weiss 		case nct6793:
3880c3963bc0SZev Weiss 			data->temp_label = nct6793_temp_label;
3881c3963bc0SZev Weiss 			data->temp_mask = NCT6793_TEMP_MASK;
3882c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
3883c3963bc0SZev Weiss 			break;
3884c3963bc0SZev Weiss 		case nct6795:
3885c3963bc0SZev Weiss 		case nct6797:
3886c3963bc0SZev Weiss 			data->temp_label = nct6795_temp_label;
3887c3963bc0SZev Weiss 			data->temp_mask = NCT6795_TEMP_MASK;
3888c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
3889c3963bc0SZev Weiss 			break;
3890c3963bc0SZev Weiss 		case nct6796:
3891c3963bc0SZev Weiss 			data->temp_label = nct6796_temp_label;
3892c3963bc0SZev Weiss 			data->temp_mask = NCT6796_TEMP_MASK;
3893c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
3894c3963bc0SZev Weiss 			break;
3895c3963bc0SZev Weiss 		case nct6798:
3896c3963bc0SZev Weiss 			data->temp_label = nct6798_temp_label;
3897c3963bc0SZev Weiss 			data->temp_mask = NCT6798_TEMP_MASK;
3898c3963bc0SZev Weiss 			data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
3899c3963bc0SZev Weiss 			break;
3900aee395bbSGuenter Roeck 		case nct6799:
3901aee395bbSGuenter Roeck 			data->temp_label = nct6799_temp_label;
3902aee395bbSGuenter Roeck 			data->temp_mask = NCT6799_TEMP_MASK;
3903aee395bbSGuenter Roeck 			data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
3904aee395bbSGuenter Roeck 			break;
3905c3963bc0SZev Weiss 		}
3906c3963bc0SZev Weiss 
3907c3963bc0SZev Weiss 		data->REG_CONFIG = NCT6775_REG_CONFIG;
3908c3963bc0SZev Weiss 		data->REG_VBAT = NCT6775_REG_VBAT;
3909c3963bc0SZev Weiss 		data->REG_DIODE = NCT6775_REG_DIODE;
3910c3963bc0SZev Weiss 		data->DIODE_MASK = NCT6775_DIODE_MASK;
3911c3963bc0SZev Weiss 		data->REG_VIN = NCT6779_REG_IN;
3912c3963bc0SZev Weiss 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3913c3963bc0SZev Weiss 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3914c3963bc0SZev Weiss 		data->REG_TARGET = NCT6775_REG_TARGET;
3915c3963bc0SZev Weiss 		data->REG_FAN = NCT6779_REG_FAN;
3916c3963bc0SZev Weiss 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3917c3963bc0SZev Weiss 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3918c3963bc0SZev Weiss 		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3919c3963bc0SZev Weiss 		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3920c3963bc0SZev Weiss 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3921c3963bc0SZev Weiss 		data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3922c3963bc0SZev Weiss 		data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
3923c3963bc0SZev Weiss 		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3924c3963bc0SZev Weiss 		data->REG_PWM[0] = NCT6775_REG_PWM;
3925c3963bc0SZev Weiss 		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3926c3963bc0SZev Weiss 		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3927c3963bc0SZev Weiss 		data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3928c3963bc0SZev Weiss 		data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
3929c3963bc0SZev Weiss 		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3930c3963bc0SZev Weiss 		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3931c3963bc0SZev Weiss 		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3932c3963bc0SZev Weiss 		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3933c3963bc0SZev Weiss 		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3934c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3935c3963bc0SZev Weiss 		data->REG_CRITICAL_TEMP_TOLERANCE
3936c3963bc0SZev Weiss 		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3937c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3938c3963bc0SZev Weiss 		data->CRITICAL_PWM_ENABLE_MASK
3939c3963bc0SZev Weiss 		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3940c3963bc0SZev Weiss 		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3941c3963bc0SZev Weiss 		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3942c3963bc0SZev Weiss 		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3943c3963bc0SZev Weiss 		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
3944c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3945c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3946c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3947c3963bc0SZev Weiss 		data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
3948c3963bc0SZev Weiss 		data->REG_ALARM = NCT6791_REG_ALARM;
3949c3963bc0SZev Weiss 		if (data->kind == nct6791)
3950c3963bc0SZev Weiss 			data->REG_BEEP = NCT6776_REG_BEEP;
3951c3963bc0SZev Weiss 		else
3952c3963bc0SZev Weiss 			data->REG_BEEP = NCT6792_REG_BEEP;
3953c3963bc0SZev Weiss 		switch (data->kind) {
3954c3963bc0SZev Weiss 		case nct6791:
3955c3963bc0SZev Weiss 		case nct6792:
3956c3963bc0SZev Weiss 		case nct6793:
3957c3963bc0SZev Weiss 			data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP;
3958c3963bc0SZev Weiss 			num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP);
3959c3963bc0SZev Weiss 			break;
3960c3963bc0SZev Weiss 		case nct6795:
3961c3963bc0SZev Weiss 		case nct6796:
3962c3963bc0SZev Weiss 		case nct6797:
3963c3963bc0SZev Weiss 		case nct6798:
3964aee395bbSGuenter Roeck 		case nct6799:
3965c3963bc0SZev Weiss 			data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
3966c3963bc0SZev Weiss 			num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
3967c3963bc0SZev Weiss 			break;
3968c3963bc0SZev Weiss 		default:
3969c3963bc0SZev Weiss 			num_reg_tsi_temp = 0;
3970c3963bc0SZev Weiss 			break;
3971c3963bc0SZev Weiss 		}
3972c3963bc0SZev Weiss 
397313558a2eSAhmad Khalifa 		if (data->kind == nct6798 || data->kind == nct6799)
397413558a2eSAhmad Khalifa 			data->scale_in = scale_in_6798;
397513558a2eSAhmad Khalifa 
3976c3963bc0SZev Weiss 		reg_temp = NCT6779_REG_TEMP;
3977c3963bc0SZev Weiss 		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
3978c3963bc0SZev Weiss 		if (data->kind == nct6791) {
3979c3963bc0SZev Weiss 			reg_temp_mon = NCT6779_REG_TEMP_MON;
3980c3963bc0SZev Weiss 			num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3981c3963bc0SZev Weiss 		} else {
3982c3963bc0SZev Weiss 			reg_temp_mon = NCT6792_REG_TEMP_MON;
3983c3963bc0SZev Weiss 			num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3984c3963bc0SZev Weiss 		}
3985c3963bc0SZev Weiss 		reg_temp_over = NCT6779_REG_TEMP_OVER;
3986c3963bc0SZev Weiss 		reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3987c3963bc0SZev Weiss 		reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3988c3963bc0SZev Weiss 		reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3989c3963bc0SZev Weiss 		reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3990c3963bc0SZev Weiss 
3991c3963bc0SZev Weiss 		break;
3992c3963bc0SZev Weiss 	default:
3993c3963bc0SZev Weiss 		return -ENODEV;
3994c3963bc0SZev Weiss 	}
3995c3963bc0SZev Weiss 	data->have_in = BIT(data->in_num) - 1;
3996c3963bc0SZev Weiss 	data->have_temp = 0;
3997c3963bc0SZev Weiss 
3998c3963bc0SZev Weiss 	/*
3999c3963bc0SZev Weiss 	 * On some boards, not all available temperature sources are monitored,
4000c3963bc0SZev Weiss 	 * even though some of the monitoring registers are unused.
4001c3963bc0SZev Weiss 	 * Get list of unused monitoring registers, then detect if any fan
4002c3963bc0SZev Weiss 	 * controls are configured to use unmonitored temperature sources.
4003c3963bc0SZev Weiss 	 * If so, assign the unmonitored temperature sources to available
4004c3963bc0SZev Weiss 	 * monitoring registers.
4005c3963bc0SZev Weiss 	 */
4006c3963bc0SZev Weiss 	mask = 0;
4007c3963bc0SZev Weiss 	available = 0;
4008c3963bc0SZev Weiss 	for (i = 0; i < num_reg_temp; i++) {
4009c3963bc0SZev Weiss 		if (reg_temp[i] == 0)
4010c3963bc0SZev Weiss 			continue;
4011c3963bc0SZev Weiss 
4012c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SOURCE[i], &src);
4013c3963bc0SZev Weiss 		if (err)
4014c3963bc0SZev Weiss 			return err;
4015c3963bc0SZev Weiss 		src &= 0x1f;
4016c3963bc0SZev Weiss 		if (!src || (mask & BIT(src)))
4017c3963bc0SZev Weiss 			available |= BIT(i);
4018c3963bc0SZev Weiss 
4019c3963bc0SZev Weiss 		mask |= BIT(src);
4020c3963bc0SZev Weiss 	}
4021c3963bc0SZev Weiss 
4022c3963bc0SZev Weiss 	/*
4023c3963bc0SZev Weiss 	 * Now find unmonitored temperature registers and enable monitoring
4024c3963bc0SZev Weiss 	 * if additional monitoring registers are available.
4025c3963bc0SZev Weiss 	 */
4026c3963bc0SZev Weiss 	err = add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4027c3963bc0SZev Weiss 	if (err)
4028c3963bc0SZev Weiss 		return err;
4029c3963bc0SZev Weiss 	err = add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4030c3963bc0SZev Weiss 	if (err)
4031c3963bc0SZev Weiss 		return err;
4032c3963bc0SZev Weiss 
4033c3963bc0SZev Weiss 	mask = 0;
4034c3963bc0SZev Weiss 	s = NUM_TEMP_FIXED;	/* First dynamic temperature attribute */
4035c3963bc0SZev Weiss 	for (i = 0; i < num_reg_temp; i++) {
4036c3963bc0SZev Weiss 		if (reg_temp[i] == 0)
4037c3963bc0SZev Weiss 			continue;
4038c3963bc0SZev Weiss 
4039c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SOURCE[i], &src);
4040c3963bc0SZev Weiss 		if (err)
4041c3963bc0SZev Weiss 			return err;
4042c3963bc0SZev Weiss 		src &= 0x1f;
4043c3963bc0SZev Weiss 		if (!src || (mask & BIT(src)))
4044c3963bc0SZev Weiss 			continue;
4045c3963bc0SZev Weiss 
4046c3963bc0SZev Weiss 		if (!(data->temp_mask & BIT(src))) {
4047c3963bc0SZev Weiss 			dev_info(dev,
4048c3963bc0SZev Weiss 				 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4049c3963bc0SZev Weiss 				 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4050c3963bc0SZev Weiss 			continue;
4051c3963bc0SZev Weiss 		}
4052c3963bc0SZev Weiss 
4053c3963bc0SZev Weiss 		mask |= BIT(src);
4054c3963bc0SZev Weiss 
4055c3963bc0SZev Weiss 		/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4056c3963bc0SZev Weiss 		if (src <= data->temp_fixed_num) {
4057c3963bc0SZev Weiss 			data->have_temp |= BIT(src - 1);
4058c3963bc0SZev Weiss 			data->have_temp_fixed |= BIT(src - 1);
4059c3963bc0SZev Weiss 			data->reg_temp[0][src - 1] = reg_temp[i];
4060c3963bc0SZev Weiss 			data->reg_temp[1][src - 1] = reg_temp_over[i];
4061c3963bc0SZev Weiss 			data->reg_temp[2][src - 1] = reg_temp_hyst[i];
4062c3963bc0SZev Weiss 			if (reg_temp_crit_h && reg_temp_crit_h[i])
4063c3963bc0SZev Weiss 				data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4064c3963bc0SZev Weiss 			else if (reg_temp_crit[src - 1])
4065c3963bc0SZev Weiss 				data->reg_temp[3][src - 1]
4066c3963bc0SZev Weiss 				  = reg_temp_crit[src - 1];
4067c3963bc0SZev Weiss 			if (reg_temp_crit_l && reg_temp_crit_l[i])
4068c3963bc0SZev Weiss 				data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
4069c3963bc0SZev Weiss 			data->reg_temp_config[src - 1] = reg_temp_config[i];
4070c3963bc0SZev Weiss 			data->temp_src[src - 1] = src;
4071c3963bc0SZev Weiss 			continue;
4072c3963bc0SZev Weiss 		}
4073c3963bc0SZev Weiss 
4074c3963bc0SZev Weiss 		if (s >= NUM_TEMP)
4075c3963bc0SZev Weiss 			continue;
4076c3963bc0SZev Weiss 
4077c3963bc0SZev Weiss 		/* Use dynamic index for other sources */
4078c3963bc0SZev Weiss 		data->have_temp |= BIT(s);
4079c3963bc0SZev Weiss 		data->reg_temp[0][s] = reg_temp[i];
4080c3963bc0SZev Weiss 		data->reg_temp[1][s] = reg_temp_over[i];
4081c3963bc0SZev Weiss 		data->reg_temp[2][s] = reg_temp_hyst[i];
4082c3963bc0SZev Weiss 		data->reg_temp_config[s] = reg_temp_config[i];
4083c3963bc0SZev Weiss 		if (reg_temp_crit_h && reg_temp_crit_h[i])
4084c3963bc0SZev Weiss 			data->reg_temp[3][s] = reg_temp_crit_h[i];
4085c3963bc0SZev Weiss 		else if (reg_temp_crit[src - 1])
4086c3963bc0SZev Weiss 			data->reg_temp[3][s] = reg_temp_crit[src - 1];
4087c3963bc0SZev Weiss 		if (reg_temp_crit_l && reg_temp_crit_l[i])
4088c3963bc0SZev Weiss 			data->reg_temp[4][s] = reg_temp_crit_l[i];
4089c3963bc0SZev Weiss 
4090c3963bc0SZev Weiss 		data->temp_src[s] = src;
4091c3963bc0SZev Weiss 		s++;
4092c3963bc0SZev Weiss 	}
4093c3963bc0SZev Weiss 
4094c3963bc0SZev Weiss 	/*
4095c3963bc0SZev Weiss 	 * Repeat with temperatures used for fan control.
4096c3963bc0SZev Weiss 	 * This set of registers does not support limits.
4097c3963bc0SZev Weiss 	 */
4098c3963bc0SZev Weiss 	for (i = 0; i < num_reg_temp_mon; i++) {
4099c3963bc0SZev Weiss 		if (reg_temp_mon[i] == 0)
4100c3963bc0SZev Weiss 			continue;
4101c3963bc0SZev Weiss 
4102c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TEMP_SEL[i], &src);
4103c3963bc0SZev Weiss 		if (err)
4104c3963bc0SZev Weiss 			return err;
4105c3963bc0SZev Weiss 		src &= 0x1f;
4106c3963bc0SZev Weiss 		if (!src)
4107c3963bc0SZev Weiss 			continue;
4108c3963bc0SZev Weiss 
4109c3963bc0SZev Weiss 		if (!(data->temp_mask & BIT(src))) {
4110c3963bc0SZev Weiss 			dev_info(dev,
4111c3963bc0SZev Weiss 				 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4112c3963bc0SZev Weiss 				 src, i, data->REG_TEMP_SEL[i],
4113c3963bc0SZev Weiss 				 reg_temp_mon[i]);
4114c3963bc0SZev Weiss 			continue;
4115c3963bc0SZev Weiss 		}
4116c3963bc0SZev Weiss 
4117c3963bc0SZev Weiss 		/*
4118c3963bc0SZev Weiss 		 * For virtual temperature sources, the 'virtual' temperature
4119c3963bc0SZev Weiss 		 * for each fan reflects a different temperature, and there
4120c3963bc0SZev Weiss 		 * are no duplicates.
4121c3963bc0SZev Weiss 		 */
4122c3963bc0SZev Weiss 		if (!(data->virt_temp_mask & BIT(src))) {
4123c3963bc0SZev Weiss 			if (mask & BIT(src))
4124c3963bc0SZev Weiss 				continue;
4125c3963bc0SZev Weiss 			mask |= BIT(src);
4126c3963bc0SZev Weiss 		}
4127c3963bc0SZev Weiss 
4128c3963bc0SZev Weiss 		/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4129c3963bc0SZev Weiss 		if (src <= data->temp_fixed_num) {
4130c3963bc0SZev Weiss 			if (data->have_temp & BIT(src - 1))
4131c3963bc0SZev Weiss 				continue;
4132c3963bc0SZev Weiss 			data->have_temp |= BIT(src - 1);
4133c3963bc0SZev Weiss 			data->have_temp_fixed |= BIT(src - 1);
4134c3963bc0SZev Weiss 			data->reg_temp[0][src - 1] = reg_temp_mon[i];
4135c3963bc0SZev Weiss 			data->temp_src[src - 1] = src;
4136c3963bc0SZev Weiss 			continue;
4137c3963bc0SZev Weiss 		}
4138c3963bc0SZev Weiss 
4139c3963bc0SZev Weiss 		if (s >= NUM_TEMP)
4140c3963bc0SZev Weiss 			continue;
4141c3963bc0SZev Weiss 
4142c3963bc0SZev Weiss 		/* Use dynamic index for other sources */
4143c3963bc0SZev Weiss 		data->have_temp |= BIT(s);
4144c3963bc0SZev Weiss 		data->reg_temp[0][s] = reg_temp_mon[i];
4145c3963bc0SZev Weiss 		data->temp_src[s] = src;
4146c3963bc0SZev Weiss 		s++;
4147c3963bc0SZev Weiss 	}
4148c3963bc0SZev Weiss 
4149c3963bc0SZev Weiss #ifdef USE_ALTERNATE
4150c3963bc0SZev Weiss 	/*
4151c3963bc0SZev Weiss 	 * Go through the list of alternate temp registers and enable
4152c3963bc0SZev Weiss 	 * if possible.
4153c3963bc0SZev Weiss 	 * The temperature is already monitored if the respective bit in <mask>
4154c3963bc0SZev Weiss 	 * is set.
4155c3963bc0SZev Weiss 	 */
4156c3963bc0SZev Weiss 	for (i = 0; i < 31; i++) {
4157c3963bc0SZev Weiss 		if (!(data->temp_mask & BIT(i + 1)))
4158c3963bc0SZev Weiss 			continue;
4159c3963bc0SZev Weiss 		if (!reg_temp_alternate[i])
4160c3963bc0SZev Weiss 			continue;
4161c3963bc0SZev Weiss 		if (mask & BIT(i + 1))
4162c3963bc0SZev Weiss 			continue;
4163c3963bc0SZev Weiss 		if (i < data->temp_fixed_num) {
4164c3963bc0SZev Weiss 			if (data->have_temp & BIT(i))
4165c3963bc0SZev Weiss 				continue;
4166c3963bc0SZev Weiss 			data->have_temp |= BIT(i);
4167c3963bc0SZev Weiss 			data->have_temp_fixed |= BIT(i);
4168c3963bc0SZev Weiss 			data->reg_temp[0][i] = reg_temp_alternate[i];
4169c3963bc0SZev Weiss 			if (i < num_reg_temp) {
4170c3963bc0SZev Weiss 				data->reg_temp[1][i] = reg_temp_over[i];
4171c3963bc0SZev Weiss 				data->reg_temp[2][i] = reg_temp_hyst[i];
4172c3963bc0SZev Weiss 			}
4173c3963bc0SZev Weiss 			data->temp_src[i] = i + 1;
4174c3963bc0SZev Weiss 			continue;
4175c3963bc0SZev Weiss 		}
4176c3963bc0SZev Weiss 
4177c3963bc0SZev Weiss 		if (s >= NUM_TEMP)	/* Abort if no more space */
4178c3963bc0SZev Weiss 			break;
4179c3963bc0SZev Weiss 
4180c3963bc0SZev Weiss 		data->have_temp |= BIT(s);
4181c3963bc0SZev Weiss 		data->reg_temp[0][s] = reg_temp_alternate[i];
4182c3963bc0SZev Weiss 		data->temp_src[s] = i + 1;
4183c3963bc0SZev Weiss 		s++;
4184c3963bc0SZev Weiss 	}
4185c3963bc0SZev Weiss #endif /* USE_ALTERNATE */
4186c3963bc0SZev Weiss 
4187c3963bc0SZev Weiss 	/* Check which TSIx_TEMP registers are active */
4188c3963bc0SZev Weiss 	for (i = 0; i < num_reg_tsi_temp; i++) {
4189c3963bc0SZev Weiss 		u16 tmp;
4190c3963bc0SZev Weiss 
4191c3963bc0SZev Weiss 		err = nct6775_read_value(data, data->REG_TSI_TEMP[i], &tmp);
4192c3963bc0SZev Weiss 		if (err)
4193c3963bc0SZev Weiss 			return err;
4194c3963bc0SZev Weiss 		if (tmp)
4195c3963bc0SZev Weiss 			data->have_tsi_temp |= BIT(i);
4196c3963bc0SZev Weiss 	}
4197c3963bc0SZev Weiss 
4198c3963bc0SZev Weiss 	/* Initialize the chip */
4199c3963bc0SZev Weiss 	err = nct6775_init_device(data);
4200c3963bc0SZev Weiss 	if (err)
4201c3963bc0SZev Weiss 		return err;
4202c3963bc0SZev Weiss 
4203c3963bc0SZev Weiss 	if (data->driver_init) {
4204c3963bc0SZev Weiss 		err = data->driver_init(data);
4205c3963bc0SZev Weiss 		if (err)
4206c3963bc0SZev Weiss 			return err;
4207c3963bc0SZev Weiss 	}
4208c3963bc0SZev Weiss 
4209c3963bc0SZev Weiss 	/* Read fan clock dividers immediately */
4210c3963bc0SZev Weiss 	err = nct6775_init_fan_common(dev, data);
4211c3963bc0SZev Weiss 	if (err)
4212c3963bc0SZev Weiss 		return err;
4213c3963bc0SZev Weiss 
4214c3963bc0SZev Weiss 	/* Register sysfs hooks */
4215c3963bc0SZev Weiss 	err = nct6775_add_template_attr_group(dev, data, &nct6775_pwm_template_group,
4216c3963bc0SZev Weiss 					      data->pwm_num);
4217c3963bc0SZev Weiss 	if (err)
4218c3963bc0SZev Weiss 		return err;
4219c3963bc0SZev Weiss 
4220c3963bc0SZev Weiss 	err = nct6775_add_template_attr_group(dev, data, &nct6775_in_template_group,
4221c3963bc0SZev Weiss 					      fls(data->have_in));
4222c3963bc0SZev Weiss 	if (err)
4223c3963bc0SZev Weiss 		return err;
4224c3963bc0SZev Weiss 
4225c3963bc0SZev Weiss 	err = nct6775_add_template_attr_group(dev, data, &nct6775_fan_template_group,
4226c3963bc0SZev Weiss 					      fls(data->has_fan));
4227c3963bc0SZev Weiss 	if (err)
4228c3963bc0SZev Weiss 		return err;
4229c3963bc0SZev Weiss 
4230c3963bc0SZev Weiss 	err = nct6775_add_template_attr_group(dev, data, &nct6775_temp_template_group,
4231c3963bc0SZev Weiss 					      fls(data->have_temp));
4232c3963bc0SZev Weiss 	if (err)
4233c3963bc0SZev Weiss 		return err;
4234c3963bc0SZev Weiss 
4235c3963bc0SZev Weiss 	if (data->have_tsi_temp) {
4236c3963bc0SZev Weiss 		tsi_temp_tg.templates = nct6775_tsi_temp_template;
4237c3963bc0SZev Weiss 		tsi_temp_tg.is_visible = nct6775_tsi_temp_is_visible;
4238c3963bc0SZev Weiss 		tsi_temp_tg.base = fls(data->have_temp) + 1;
4239c3963bc0SZev Weiss 		err = nct6775_add_template_attr_group(dev, data, &tsi_temp_tg,
4240c3963bc0SZev Weiss 						      fls(data->have_tsi_temp));
4241c3963bc0SZev Weiss 		if (err)
4242c3963bc0SZev Weiss 			return err;
4243c3963bc0SZev Weiss 	}
4244c3963bc0SZev Weiss 
4245c3963bc0SZev Weiss 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4246c3963bc0SZev Weiss 							   data, data->groups);
4247c3963bc0SZev Weiss 	return PTR_ERR_OR_ZERO(hwmon_dev);
4248c3963bc0SZev Weiss }
4249c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_probe);
4250c3963bc0SZev Weiss 
4251c3963bc0SZev Weiss MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
4252c3963bc0SZev Weiss MODULE_DESCRIPTION("Core driver for NCT6775F and compatible chips");
4253c3963bc0SZev Weiss MODULE_LICENSE("GPL");
4254