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