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