blob: 3a9bb6671f291993ca42418ecbd4301fca40d91c [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
8 * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org>
9 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070041 *
42 * #temp lists the number of monitored temperature sources (first value) plus
43 * the number of directly connectable temperature sensors (second value).
44 */
45
46#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
47
48#include <linux/module.h>
49#include <linux/init.h>
50#include <linux/slab.h>
51#include <linux/jiffies.h>
52#include <linux/platform_device.h>
53#include <linux/hwmon.h>
54#include <linux/hwmon-sysfs.h>
55#include <linux/hwmon-vid.h>
56#include <linux/err.h>
57#include <linux/mutex.h>
58#include <linux/acpi.h>
59#include <linux/io.h>
60#include "lm75.h"
61
Guenter Roeckaa136e52012-12-04 03:26:05 -080062#define USE_ALTERNATE
63
David Bartley578ab5f2013-06-24 22:28:28 -070064enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065
66/* used to set data->name = nct6775_device_names[data->sio_kind] */
67static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070068 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070069 "nct6775",
70 "nct6776",
71 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070072 "nct6791",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070073};
74
75static unsigned short force_id;
76module_param(force_id, ushort, 0);
77MODULE_PARM_DESC(force_id, "Override the detected device ID");
78
Guenter Roeck47ece962012-12-04 07:59:32 -080079static unsigned short fan_debounce;
80module_param(fan_debounce, ushort, 0);
81MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
82
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070083#define DRVNAME "nct6775"
84
85/*
86 * Super-I/O constants and functions
87 */
88
Guenter Roecka6bd5872012-12-04 03:13:34 -080089#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070090#define NCT6775_LD_HWM 0x0b
91#define NCT6775_LD_VID 0x0d
92
93#define SIO_REG_LDSEL 0x07 /* Logical device select */
94#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
95#define SIO_REG_ENABLE 0x30 /* Logical device enable */
96#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
97
Guenter Roeck6c009502012-07-01 08:23:15 -070098#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070099#define SIO_NCT6775_ID 0xb470
100#define SIO_NCT6776_ID 0xc330
101#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700102#define SIO_NCT6791_ID 0xc800
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700103#define SIO_ID_MASK 0xFFF0
104
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800105enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
106
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700107static inline void
108superio_outb(int ioreg, int reg, int val)
109{
110 outb(reg, ioreg);
111 outb(val, ioreg + 1);
112}
113
114static inline int
115superio_inb(int ioreg, int reg)
116{
117 outb(reg, ioreg);
118 return inb(ioreg + 1);
119}
120
121static inline void
122superio_select(int ioreg, int ld)
123{
124 outb(SIO_REG_LDSEL, ioreg);
125 outb(ld, ioreg + 1);
126}
127
128static inline int
129superio_enter(int ioreg)
130{
131 /*
132 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
133 */
134 if (!request_muxed_region(ioreg, 2, DRVNAME))
135 return -EBUSY;
136
137 outb(0x87, ioreg);
138 outb(0x87, ioreg);
139
140 return 0;
141}
142
143static inline void
144superio_exit(int ioreg)
145{
146 outb(0xaa, ioreg);
147 outb(0x02, ioreg);
148 outb(0x02, ioreg + 1);
149 release_region(ioreg, 2);
150}
151
152/*
153 * ISA constants
154 */
155
156#define IOREGION_ALIGNMENT (~7)
157#define IOREGION_OFFSET 5
158#define IOREGION_LENGTH 2
159#define ADDR_REG_OFFSET 0
160#define DATA_REG_OFFSET 1
161
162#define NCT6775_REG_BANK 0x4E
163#define NCT6775_REG_CONFIG 0x40
164
165/*
166 * Not currently used:
167 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
168 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
169 * REG_MAN_ID is at port 0x4f
170 * REG_CHIP_ID is at port 0x58
171 */
172
Guenter Roeckaa136e52012-12-04 03:26:05 -0800173#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
174#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
175
Guenter Roeck6c009502012-07-01 08:23:15 -0700176#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700177#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700178
David Bartley578ab5f2013-06-24 22:28:28 -0700179#define NUM_FAN 6
180
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700181/* Common and NCT6775 specific data */
182
183/* Voltage min/max registers for nr=7..14 are in bank 5 */
184
185static const u16 NCT6775_REG_IN_MAX[] = {
186 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
187 0x55c, 0x55e, 0x560, 0x562 };
188static const u16 NCT6775_REG_IN_MIN[] = {
189 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
190 0x55d, 0x55f, 0x561, 0x563 };
191static const u16 NCT6775_REG_IN[] = {
192 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
193};
194
195#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800196#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700197#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700198
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800199#define NCT6775_REG_FANDIV1 0x506
200#define NCT6775_REG_FANDIV2 0x507
201
Guenter Roeck47ece962012-12-04 07:59:32 -0800202#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
203
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700204static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
205
Guenter Roeck30846992013-06-24 22:21:59 -0700206/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700207
208static const s8 NCT6775_ALARM_BITS[] = {
209 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
210 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
211 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700212 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700213 -1, -1, -1, /* unused */
214 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
215 12, -1 }; /* intrusion0, intrusion1 */
216
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800217#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800218#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800219#define INTRUSION_ALARM_BASE 30
220
Guenter Roeck30846992013-06-24 22:21:59 -0700221static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
222
223/*
224 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
225 * 30..31 intrusion
226 */
227static const s8 NCT6775_BEEP_BITS[] = {
228 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
229 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
230 21, /* global beep enable */
231 6, 7, 11, 28, -1, /* fan1..fan5 */
232 -1, -1, -1, /* unused */
233 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
234 12, -1 }; /* intrusion0, intrusion1 */
235
236#define BEEP_ENABLE_BASE 15
237
Guenter Roecka6bd5872012-12-04 03:13:34 -0800238static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
239static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
240
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800241/* DC or PWM output fan configuration */
242static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
243static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
244
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800245/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800246
David Bartley578ab5f2013-06-24 22:28:28 -0700247static const u16 NCT6775_REG_TARGET[] = {
248 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
249static const u16 NCT6775_REG_FAN_MODE[] = {
250 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800251static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700252 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800253static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700254 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800255static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700256 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
257static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
258 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800259static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
260static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
261
262static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700263 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
264static const u16 NCT6775_REG_PWM[] = {
265 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
266static const u16 NCT6775_REG_PWM_READ[] = {
267 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800268
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800269static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
270static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800271static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700272static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800273
Guenter Roeckaa136e52012-12-04 03:26:05 -0800274static const u16 NCT6775_REG_TEMP[] = {
275 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
276
277static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
278 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
279static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
280 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
281static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
282 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
283
284static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
285 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
286
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800287static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700288 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800289
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800290static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700291 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800292static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700293 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800294static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700295 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800296static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700297 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800298static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700299 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800300
Guenter Roeckaa136e52012-12-04 03:26:05 -0800301static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
302
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800303static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700304 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800305static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700306 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800307
308#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
309#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
310
311static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
312
313static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700314 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800315static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800317
Guenter Roeckaa136e52012-12-04 03:26:05 -0800318static const char *const nct6775_temp_label[] = {
319 "",
320 "SYSTIN",
321 "CPUTIN",
322 "AUXTIN",
323 "AMD SB-TSI",
324 "PECI Agent 0",
325 "PECI Agent 1",
326 "PECI Agent 2",
327 "PECI Agent 3",
328 "PECI Agent 4",
329 "PECI Agent 5",
330 "PECI Agent 6",
331 "PECI Agent 7",
332 "PCH_CHIP_CPU_MAX_TEMP",
333 "PCH_CHIP_TEMP",
334 "PCH_CPU_TEMP",
335 "PCH_MCH_TEMP",
336 "PCH_DIM0_TEMP",
337 "PCH_DIM1_TEMP",
338 "PCH_DIM2_TEMP",
339 "PCH_DIM3_TEMP"
340};
341
342static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
343 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
344
345static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
346 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
347 0xa07 };
348
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700349/* NCT6776 specific data */
350
351static const s8 NCT6776_ALARM_BITS[] = {
352 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
353 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
354 -1, /* unused */
355 6, 7, 11, 10, 23, /* fan1..fan5 */
356 -1, -1, -1, /* unused */
357 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
358 12, 9 }; /* intrusion0, intrusion1 */
359
Guenter Roeck30846992013-06-24 22:21:59 -0700360static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
361
362static const s8 NCT6776_BEEP_BITS[] = {
363 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
364 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
365 24, /* global beep enable */
366 25, 26, 27, 28, 29, /* fan1..fan5 */
367 -1, -1, -1, /* unused */
368 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
369 30, 31 }; /* intrusion0, intrusion1 */
370
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800371static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700372 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800373
David Bartley578ab5f2013-06-24 22:28:28 -0700374static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
375static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800376
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800377static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800378static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800379
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800380static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700381 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800382
Guenter Roeckaa136e52012-12-04 03:26:05 -0800383static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
384 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
385
386static const char *const nct6776_temp_label[] = {
387 "",
388 "SYSTIN",
389 "CPUTIN",
390 "AUXTIN",
391 "SMBUSMASTER 0",
392 "SMBUSMASTER 1",
393 "SMBUSMASTER 2",
394 "SMBUSMASTER 3",
395 "SMBUSMASTER 4",
396 "SMBUSMASTER 5",
397 "SMBUSMASTER 6",
398 "SMBUSMASTER 7",
399 "PECI Agent 0",
400 "PECI Agent 1",
401 "PCH_CHIP_CPU_MAX_TEMP",
402 "PCH_CHIP_TEMP",
403 "PCH_CPU_TEMP",
404 "PCH_MCH_TEMP",
405 "PCH_DIM0_TEMP",
406 "PCH_DIM1_TEMP",
407 "PCH_DIM2_TEMP",
408 "PCH_DIM3_TEMP",
409 "BYTE_TEMP"
410};
411
412static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
413 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
414
415static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
416 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
417
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700418/* NCT6779 specific data */
419
420static const u16 NCT6779_REG_IN[] = {
421 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
422 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
423
424static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
425 0x459, 0x45A, 0x45B, 0x568 };
426
427static const s8 NCT6779_ALARM_BITS[] = {
428 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
429 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
430 -1, /* unused */
431 6, 7, 11, 10, 23, /* fan1..fan5 */
432 -1, -1, -1, /* unused */
433 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
434 12, 9 }; /* intrusion0, intrusion1 */
435
Guenter Roeck30846992013-06-24 22:21:59 -0700436static const s8 NCT6779_BEEP_BITS[] = {
437 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
438 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
439 24, /* global beep enable */
440 25, 26, 27, 28, 29, /* fan1..fan5 */
441 -1, -1, -1, /* unused */
442 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
443 30, 31 }; /* intrusion0, intrusion1 */
444
David Bartley578ab5f2013-06-24 22:28:28 -0700445static const u16 NCT6779_REG_FAN[] = {
446 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800447static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700448 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800449
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800450static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700451 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700452#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800453static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700454 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800455
Guenter Roeckaa136e52012-12-04 03:26:05 -0800456static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
457static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
458 0x18, 0x152 };
459static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
460 0x3a, 0x153 };
461static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
462 0x39, 0x155 };
463
464static const u16 NCT6779_REG_TEMP_OFFSET[] = {
465 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
466
467static const char *const nct6779_temp_label[] = {
468 "",
469 "SYSTIN",
470 "CPUTIN",
471 "AUXTIN0",
472 "AUXTIN1",
473 "AUXTIN2",
474 "AUXTIN3",
475 "",
476 "SMBUSMASTER 0",
477 "SMBUSMASTER 1",
478 "SMBUSMASTER 2",
479 "SMBUSMASTER 3",
480 "SMBUSMASTER 4",
481 "SMBUSMASTER 5",
482 "SMBUSMASTER 6",
483 "SMBUSMASTER 7",
484 "PECI Agent 0",
485 "PECI Agent 1",
486 "PCH_CHIP_CPU_MAX_TEMP",
487 "PCH_CHIP_TEMP",
488 "PCH_CPU_TEMP",
489 "PCH_MCH_TEMP",
490 "PCH_DIM0_TEMP",
491 "PCH_DIM1_TEMP",
492 "PCH_DIM2_TEMP",
493 "PCH_DIM3_TEMP",
494 "BYTE_TEMP"
495};
496
497static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
498 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
499 0, 0, 0, 0, 0, 0, 0, 0,
500 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
501 0x408, 0 };
502
503static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
504 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
505
David Bartley578ab5f2013-06-24 22:28:28 -0700506/* NCT6791 specific data */
507
508#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
509
510static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
511 0x459, 0x45A, 0x45B, 0x568, 0x45D };
512
513static const s8 NCT6791_ALARM_BITS[] = {
514 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
515 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
516 -1, /* unused */
517 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
518 -1, -1, /* unused */
519 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
520 12, 9 }; /* intrusion0, intrusion1 */
521
522
Guenter Roeck6c009502012-07-01 08:23:15 -0700523/* NCT6102D/NCT6106D specific data */
524
525#define NCT6106_REG_VBAT 0x318
526#define NCT6106_REG_DIODE 0x319
527#define NCT6106_DIODE_MASK 0x01
528
529static const u16 NCT6106_REG_IN_MAX[] = {
530 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
531static const u16 NCT6106_REG_IN_MIN[] = {
532 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
533static const u16 NCT6106_REG_IN[] = {
534 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
535
536static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
537static const u16 NCT6106_REG_TEMP_HYST[] = {
538 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
539static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700540 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
541static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
542 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
543static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
544 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700545static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
546static const u16 NCT6106_REG_TEMP_CONFIG[] = {
547 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
548
549static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
550static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
551static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
552static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
553
554static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
555static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
556static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
557static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
558static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
559static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
560static const u16 NCT6106_REG_TEMP_SOURCE[] = {
561 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
562
563static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
564static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
565 0x11b, 0x12b, 0x13b };
566
567static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
568#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
569static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
570
571static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
572static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
573static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
574static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
575static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
576static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
577
578static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
579
580static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
581static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
582static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
583static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
584static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
585static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
586
587static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
588static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
589
590static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
591 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
592
593static const s8 NCT6106_ALARM_BITS[] = {
594 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
595 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
596 -1, /* unused */
597 32, 33, 34, -1, -1, /* fan1..fan5 */
598 -1, -1, -1, /* unused */
599 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
600 48, -1 /* intrusion0, intrusion1 */
601};
602
Guenter Roeck30846992013-06-24 22:21:59 -0700603static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
604 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
605
606static const s8 NCT6106_BEEP_BITS[] = {
607 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
608 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
609 32, /* global beep enable */
610 24, 25, 26, 27, 28, /* fan1..fan5 */
611 -1, -1, -1, /* unused */
612 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
613 34, -1 /* intrusion0, intrusion1 */
614};
615
Guenter Roeck6c009502012-07-01 08:23:15 -0700616static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
617 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
618
619static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
620 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
621
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800622static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
623{
624 if (mode == 0 && pwm == 255)
625 return off;
626 return mode + 1;
627}
628
629static int pwm_enable_to_reg(enum pwm_enable mode)
630{
631 if (mode == off)
632 return 0;
633 return mode - 1;
634}
635
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700636/*
637 * Conversions
638 */
639
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800640/* 1 is DC mode, output in ms */
641static unsigned int step_time_from_reg(u8 reg, u8 mode)
642{
643 return mode ? 400 * reg : 100 * reg;
644}
645
646static u8 step_time_to_reg(unsigned int msec, u8 mode)
647{
648 return clamp_val((mode ? (msec + 200) / 400 :
649 (msec + 50) / 100), 1, 255);
650}
651
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800652static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
653{
654 if (reg == 0 || reg == 255)
655 return 0;
656 return 1350000U / (reg << divreg);
657}
658
659static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
660{
661 if ((reg & 0xff1f) == 0xff1f)
662 return 0;
663
664 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
665
666 if (reg == 0)
667 return 0;
668
669 return 1350000U / reg;
670}
671
672static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
673{
674 if (reg == 0 || reg == 0xffff)
675 return 0;
676
677 /*
678 * Even though the registers are 16 bit wide, the fan divisor
679 * still applies.
680 */
681 return 1350000U / (reg << divreg);
682}
683
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800684static u16 fan_to_reg(u32 fan, unsigned int divreg)
685{
686 if (!fan)
687 return 0;
688
689 return (1350000U / fan) >> divreg;
690}
691
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800692static inline unsigned int
693div_from_reg(u8 reg)
694{
695 return 1 << reg;
696}
697
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700698/*
699 * Some of the voltage inputs have internal scaling, the tables below
700 * contain 8 (the ADC LSB in mV) * scaling factor * 100
701 */
702static const u16 scale_in[15] = {
703 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
704 800, 800
705};
706
707static inline long in_from_reg(u8 reg, u8 nr)
708{
709 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
710}
711
712static inline u8 in_to_reg(u32 val, u8 nr)
713{
714 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
715}
716
717/*
718 * Data structures and manipulation thereof
719 */
720
721struct nct6775_data {
722 int addr; /* IO base of hw monitor block */
723 enum kinds kind;
724 const char *name;
725
726 struct device *hwmon_dev;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700727 struct attribute_group *group_in;
728 struct attribute_group *group_fan;
729 struct attribute_group *group_temp;
730 struct attribute_group *group_pwm;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700731
Guenter Roeckb7a61352013-04-02 22:14:06 -0700732 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
733 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800734 */
735 u8 temp_src[NUM_TEMP];
736 u16 reg_temp_config[NUM_TEMP];
737 const char * const *temp_label;
738 int temp_label_num;
739
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700740 u16 REG_CONFIG;
741 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800742 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700743 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700744
745 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700746 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700747
748 const u16 *REG_VIN;
749 const u16 *REG_IN_MINMAX[2];
750
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800751 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800752 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800753 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800754 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800755 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700756 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800757 const u16 *REG_FAN_TIME[3];
758
759 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800760
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800761 const u8 *REG_PWM_MODE;
762 const u8 *PWM_MODE_MASK;
763
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800764 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
765 * [3]=pwm_max, [4]=pwm_step,
766 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800767 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800768 const u16 *REG_PWM_READ;
769
Guenter Roeck6c009502012-07-01 08:23:15 -0700770 const u16 *REG_CRITICAL_PWM_ENABLE;
771 u8 CRITICAL_PWM_ENABLE_MASK;
772 const u16 *REG_CRITICAL_PWM;
773
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800774 const u16 *REG_AUTO_TEMP;
775 const u16 *REG_AUTO_PWM;
776
777 const u16 *REG_CRITICAL_TEMP;
778 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
779
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800780 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800781 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800782 const u16 *REG_WEIGHT_TEMP_SEL;
783 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
784
Guenter Roeckaa136e52012-12-04 03:26:05 -0800785 const u16 *REG_TEMP_OFFSET;
786
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700787 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700788 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700789
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800790 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
791 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
792
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700793 struct mutex update_lock;
794 bool valid; /* true if following fields are valid */
795 unsigned long last_updated; /* In jiffies */
796
797 /* Register values */
798 u8 bank; /* current register bank */
799 u8 in_num; /* number of in inputs we have */
800 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700801 unsigned int rpm[NUM_FAN];
802 u16 fan_min[NUM_FAN];
803 u8 fan_pulses[NUM_FAN];
804 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800805 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800806 u8 has_fan; /* some fan inputs can be disabled */
807 u8 has_fan_min; /* some fans don't have min register */
808 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700809
Guenter Roeck6c009502012-07-01 08:23:15 -0700810 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700811 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800812 u8 temp_fixed_num; /* 3 or 6 */
813 u8 temp_type[NUM_TEMP_FIXED];
814 s8 temp_offset[NUM_TEMP_FIXED];
815 s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
816 * 3=temp_crit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700817 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700818 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700819
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800820 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700821 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
822 * 0->PWM variable duty cycle
823 */
824 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800825 /* 0->off
826 * 1->manual
827 * 2->thermal cruise mode (also called SmartFan I)
828 * 3->fan speed cruise mode
829 * 4->SmartFan III
830 * 5->enhanced variable thermal cruise (SmartFan IV)
831 */
David Bartley578ab5f2013-06-24 22:28:28 -0700832 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
833 * [3]=pwm_max, [4]=pwm_step,
834 * [5]=weight_duty_step, [6]=weight_duty_base
835 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800836
David Bartley578ab5f2013-06-24 22:28:28 -0700837 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800838 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700839 u32 target_speed[NUM_FAN];
840 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800841 u8 speed_tolerance_limit;
842
David Bartley578ab5f2013-06-24 22:28:28 -0700843 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800844 u8 tolerance_mask;
845
David Bartley578ab5f2013-06-24 22:28:28 -0700846 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800847
848 /* Automatic fan speed control registers */
849 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700850 u8 auto_pwm[NUM_FAN][7];
851 u8 auto_temp[NUM_FAN][7];
852 u8 pwm_temp_sel[NUM_FAN];
853 u8 pwm_weight_temp_sel[NUM_FAN];
854 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
855 * 2->temp_base
856 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800857
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700858 u8 vid;
859 u8 vrm;
860
Guenter Roeckf73cf632013-03-18 09:22:50 -0700861 bool have_vid;
862
Guenter Roeckaa136e52012-12-04 03:26:05 -0800863 u16 have_temp;
864 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700865 u16 have_in;
Guenter Roeck84d19d92012-12-04 08:01:39 -0800866#ifdef CONFIG_PM
867 /* Remember extra register values over suspend/resume */
868 u8 vbat;
869 u8 fandiv1;
870 u8 fandiv2;
871#endif
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700872};
873
874struct nct6775_sio_data {
875 int sioreg;
876 enum kinds kind;
877};
878
Guenter Roeckf73cf632013-03-18 09:22:50 -0700879struct sensor_device_template {
880 struct device_attribute dev_attr;
881 union {
882 struct {
883 u8 nr;
884 u8 index;
885 } s;
886 int index;
887 } u;
888 bool s2; /* true if both index and nr are used */
889};
890
891struct sensor_device_attr_u {
892 union {
893 struct sensor_device_attribute a1;
894 struct sensor_device_attribute_2 a2;
895 } u;
896 char name[32];
897};
898
899#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
900 .attr = {.name = _template, .mode = _mode }, \
901 .show = _show, \
902 .store = _store, \
903}
904
905#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
906 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
907 .u.index = _index, \
908 .s2 = false }
909
910#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
911 _nr, _index) \
912 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
913 .u.s.index = _index, \
914 .u.s.nr = _nr, \
915 .s2 = true }
916
917#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
918static struct sensor_device_template sensor_dev_template_##_name \
919 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
920 _index)
921
922#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
923 _nr, _index) \
924static struct sensor_device_template sensor_dev_template_##_name \
925 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
926 _nr, _index)
927
928struct sensor_template_group {
929 struct sensor_device_template **templates;
930 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
931 int base;
932};
933
934static struct attribute_group *
935nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
936 int repeat)
937{
938 struct attribute_group *group;
939 struct sensor_device_attr_u *su;
940 struct sensor_device_attribute *a;
941 struct sensor_device_attribute_2 *a2;
942 struct attribute **attrs;
943 struct sensor_device_template **t;
944 int err, i, j, count;
945
946 if (repeat <= 0)
947 return ERR_PTR(-EINVAL);
948
949 t = tg->templates;
950 for (count = 0; *t; t++, count++)
951 ;
952
953 if (count == 0)
954 return ERR_PTR(-EINVAL);
955
956 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
957 if (group == NULL)
958 return ERR_PTR(-ENOMEM);
959
960 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
961 GFP_KERNEL);
962 if (attrs == NULL)
963 return ERR_PTR(-ENOMEM);
964
965 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
966 GFP_KERNEL);
967 if (su == NULL)
968 return ERR_PTR(-ENOMEM);
969
970 group->attrs = attrs;
971 group->is_visible = tg->is_visible;
972
973 for (i = 0; i < repeat; i++) {
974 t = tg->templates;
975 for (j = 0; *t != NULL; j++) {
976 snprintf(su->name, sizeof(su->name),
977 (*t)->dev_attr.attr.name, tg->base + i);
978 if ((*t)->s2) {
979 a2 = &su->u.a2;
980 a2->dev_attr.attr.name = su->name;
981 a2->nr = (*t)->u.s.nr + i;
982 a2->index = (*t)->u.s.index;
983 a2->dev_attr.attr.mode =
984 (*t)->dev_attr.attr.mode;
985 a2->dev_attr.show = (*t)->dev_attr.show;
986 a2->dev_attr.store = (*t)->dev_attr.store;
987 *attrs = &a2->dev_attr.attr;
988 } else {
989 a = &su->u.a1;
990 a->dev_attr.attr.name = su->name;
991 a->index = (*t)->u.index + i;
992 a->dev_attr.attr.mode =
993 (*t)->dev_attr.attr.mode;
994 a->dev_attr.show = (*t)->dev_attr.show;
995 a->dev_attr.store = (*t)->dev_attr.store;
996 *attrs = &a->dev_attr.attr;
997 }
998 attrs++;
999 su++;
1000 t++;
1001 }
1002 }
1003
1004 err = sysfs_create_group(&dev->kobj, group);
1005 if (err)
1006 return ERR_PTR(-ENOMEM);
1007
1008 return group;
1009}
1010
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001011static bool is_word_sized(struct nct6775_data *data, u16 reg)
1012{
1013 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001014 case nct6106:
1015 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1016 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1017 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001018 case nct6775:
1019 return (((reg & 0xff00) == 0x100 ||
1020 (reg & 0xff00) == 0x200) &&
1021 ((reg & 0x00ff) == 0x50 ||
1022 (reg & 0x00ff) == 0x53 ||
1023 (reg & 0x00ff) == 0x55)) ||
1024 (reg & 0xfff0) == 0x630 ||
1025 reg == 0x640 || reg == 0x642 ||
1026 reg == 0x662 ||
1027 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1028 reg == 0x73 || reg == 0x75 || reg == 0x77;
1029 case nct6776:
1030 return (((reg & 0xff00) == 0x100 ||
1031 (reg & 0xff00) == 0x200) &&
1032 ((reg & 0x00ff) == 0x50 ||
1033 (reg & 0x00ff) == 0x53 ||
1034 (reg & 0x00ff) == 0x55)) ||
1035 (reg & 0xfff0) == 0x630 ||
1036 reg == 0x402 ||
1037 reg == 0x640 || reg == 0x642 ||
1038 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1039 reg == 0x73 || reg == 0x75 || reg == 0x77;
1040 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001041 case nct6791:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001042 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001043 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001044 reg == 0x402 ||
1045 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1046 reg == 0x640 || reg == 0x642 ||
1047 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
1048 reg == 0x7b;
1049 }
1050 return false;
1051}
1052
1053/*
1054 * On older chips, only registers 0x50-0x5f are banked.
1055 * On more recent chips, all registers are banked.
1056 * Assume that is the case and set the bank number for each access.
1057 * Cache the bank number so it only needs to be set if it changes.
1058 */
1059static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1060{
1061 u8 bank = reg >> 8;
1062 if (data->bank != bank) {
1063 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1064 outb_p(bank, data->addr + DATA_REG_OFFSET);
1065 data->bank = bank;
1066 }
1067}
1068
1069static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1070{
1071 int res, word_sized = is_word_sized(data, reg);
1072
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001073 nct6775_set_bank(data, reg);
1074 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1075 res = inb_p(data->addr + DATA_REG_OFFSET);
1076 if (word_sized) {
1077 outb_p((reg & 0xff) + 1,
1078 data->addr + ADDR_REG_OFFSET);
1079 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1080 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001081 return res;
1082}
1083
1084static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1085{
1086 int word_sized = is_word_sized(data, reg);
1087
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001088 nct6775_set_bank(data, reg);
1089 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1090 if (word_sized) {
1091 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1092 outb_p((reg & 0xff) + 1,
1093 data->addr + ADDR_REG_OFFSET);
1094 }
1095 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001096 return 0;
1097}
1098
Guenter Roeckaa136e52012-12-04 03:26:05 -08001099/* We left-align 8-bit temperature values to make the code simpler */
1100static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1101{
1102 u16 res;
1103
1104 res = nct6775_read_value(data, reg);
1105 if (!is_word_sized(data, reg))
1106 res <<= 8;
1107
1108 return res;
1109}
1110
1111static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1112{
1113 if (!is_word_sized(data, reg))
1114 value >>= 8;
1115 return nct6775_write_value(data, reg, value);
1116}
1117
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001118/* This function assumes that the caller holds data->update_lock */
1119static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1120{
1121 u8 reg;
1122
1123 switch (nr) {
1124 case 0:
1125 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1126 | (data->fan_div[0] & 0x7);
1127 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1128 break;
1129 case 1:
1130 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1131 | ((data->fan_div[1] << 4) & 0x70);
1132 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1133 break;
1134 case 2:
1135 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1136 | (data->fan_div[2] & 0x7);
1137 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1138 break;
1139 case 3:
1140 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1141 | ((data->fan_div[3] << 4) & 0x70);
1142 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1143 break;
1144 }
1145}
1146
1147static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1148{
1149 if (data->kind == nct6775)
1150 nct6775_write_fan_div(data, nr);
1151}
1152
1153static void nct6775_update_fan_div(struct nct6775_data *data)
1154{
1155 u8 i;
1156
1157 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1158 data->fan_div[0] = i & 0x7;
1159 data->fan_div[1] = (i & 0x70) >> 4;
1160 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1161 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001162 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001163 data->fan_div[3] = (i & 0x70) >> 4;
1164}
1165
1166static void nct6775_update_fan_div_common(struct nct6775_data *data)
1167{
1168 if (data->kind == nct6775)
1169 nct6775_update_fan_div(data);
1170}
1171
1172static void nct6775_init_fan_div(struct nct6775_data *data)
1173{
1174 int i;
1175
1176 nct6775_update_fan_div_common(data);
1177 /*
1178 * For all fans, start with highest divider value if the divider
1179 * register is not initialized. This ensures that we get a
1180 * reading from the fan count register, even if it is not optimal.
1181 * We'll compute a better divider later on.
1182 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001183 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001184 if (!(data->has_fan & (1 << i)))
1185 continue;
1186 if (data->fan_div[i] == 0) {
1187 data->fan_div[i] = 7;
1188 nct6775_write_fan_div_common(data, i);
1189 }
1190 }
1191}
1192
1193static void nct6775_init_fan_common(struct device *dev,
1194 struct nct6775_data *data)
1195{
1196 int i;
1197 u8 reg;
1198
1199 if (data->has_fan_div)
1200 nct6775_init_fan_div(data);
1201
1202 /*
1203 * If fan_min is not set (0), set it to 0xff to disable it. This
1204 * prevents the unnecessary warning when fanX_min is reported as 0.
1205 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001206 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001207 if (data->has_fan_min & (1 << i)) {
1208 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1209 if (!reg)
1210 nct6775_write_value(data, data->REG_FAN_MIN[i],
1211 data->has_fan_div ? 0xff
1212 : 0xff1f);
1213 }
1214 }
1215}
1216
1217static void nct6775_select_fan_div(struct device *dev,
1218 struct nct6775_data *data, int nr, u16 reg)
1219{
1220 u8 fan_div = data->fan_div[nr];
1221 u16 fan_min;
1222
1223 if (!data->has_fan_div)
1224 return;
1225
1226 /*
1227 * If we failed to measure the fan speed, or the reported value is not
1228 * in the optimal range, and the clock divider can be modified,
1229 * let's try that for next time.
1230 */
1231 if (reg == 0x00 && fan_div < 0x07)
1232 fan_div++;
1233 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1234 fan_div--;
1235
1236 if (fan_div != data->fan_div[nr]) {
1237 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1238 nr + 1, div_from_reg(data->fan_div[nr]),
1239 div_from_reg(fan_div));
1240
1241 /* Preserve min limit if possible */
1242 if (data->has_fan_min & (1 << nr)) {
1243 fan_min = data->fan_min[nr];
1244 if (fan_div > data->fan_div[nr]) {
1245 if (fan_min != 255 && fan_min > 1)
1246 fan_min >>= 1;
1247 } else {
1248 if (fan_min != 255) {
1249 fan_min <<= 1;
1250 if (fan_min > 254)
1251 fan_min = 254;
1252 }
1253 }
1254 if (fan_min != data->fan_min[nr]) {
1255 data->fan_min[nr] = fan_min;
1256 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1257 fan_min);
1258 }
1259 }
1260 data->fan_div[nr] = fan_div;
1261 nct6775_write_fan_div_common(data, nr);
1262 }
1263}
1264
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001265static void nct6775_update_pwm(struct device *dev)
1266{
1267 struct nct6775_data *data = dev_get_drvdata(dev);
1268 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001269 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001270 bool duty_is_dc;
1271
1272 for (i = 0; i < data->pwm_num; i++) {
1273 if (!(data->has_pwm & (1 << i)))
1274 continue;
1275
1276 duty_is_dc = data->REG_PWM_MODE[i] &&
1277 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1278 & data->PWM_MODE_MASK[i]);
1279 data->pwm_mode[i] = duty_is_dc;
1280
1281 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1282 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1283 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1284 data->pwm[j][i]
1285 = nct6775_read_value(data,
1286 data->REG_PWM[j][i]);
1287 }
1288 }
1289
1290 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1291 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001292
1293 if (!data->temp_tolerance[0][i] ||
1294 data->pwm_enable[i] != speed_cruise)
1295 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1296 if (!data->target_speed_tolerance[i] ||
1297 data->pwm_enable[i] == speed_cruise) {
1298 u8 t = fanmodecfg & 0x0f;
1299 if (data->REG_TOLERANCE_H) {
1300 t |= (nct6775_read_value(data,
1301 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1302 }
1303 data->target_speed_tolerance[i] = t;
1304 }
1305
1306 data->temp_tolerance[1][i] =
1307 nct6775_read_value(data,
1308 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1309
1310 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1311 data->pwm_temp_sel[i] = reg & 0x1f;
1312 /* If fan can stop, report floor as 0 */
1313 if (reg & 0x80)
1314 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001315
1316 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1317 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1318 /* If weight is disabled, report weight source as 0 */
1319 if (j == 1 && !(reg & 0x80))
1320 data->pwm_weight_temp_sel[i] = 0;
1321
1322 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001323 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001324 data->weight_temp[j][i]
1325 = nct6775_read_value(data,
1326 data->REG_WEIGHT_TEMP[j][i]);
1327 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001328 }
1329}
1330
1331static void nct6775_update_pwm_limits(struct device *dev)
1332{
1333 struct nct6775_data *data = dev_get_drvdata(dev);
1334 int i, j;
1335 u8 reg;
1336 u16 reg_t;
1337
1338 for (i = 0; i < data->pwm_num; i++) {
1339 if (!(data->has_pwm & (1 << i)))
1340 continue;
1341
Guenter Roeckc409fd42013-04-09 05:04:00 -07001342 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001343 data->fan_time[j][i] =
1344 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1345 }
1346
1347 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1348 /* Update only in matching mode or if never updated */
1349 if (!data->target_temp[i] ||
1350 data->pwm_enable[i] == thermal_cruise)
1351 data->target_temp[i] = reg_t & data->target_temp_mask;
1352 if (!data->target_speed[i] ||
1353 data->pwm_enable[i] == speed_cruise) {
1354 if (data->REG_TOLERANCE_H) {
1355 reg_t |= (nct6775_read_value(data,
1356 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1357 }
1358 data->target_speed[i] = reg_t;
1359 }
1360
1361 for (j = 0; j < data->auto_pwm_num; j++) {
1362 data->auto_pwm[i][j] =
1363 nct6775_read_value(data,
1364 NCT6775_AUTO_PWM(data, i, j));
1365 data->auto_temp[i][j] =
1366 nct6775_read_value(data,
1367 NCT6775_AUTO_TEMP(data, i, j));
1368 }
1369
1370 /* critical auto_pwm temperature data */
1371 data->auto_temp[i][data->auto_pwm_num] =
1372 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1373
1374 switch (data->kind) {
1375 case nct6775:
1376 reg = nct6775_read_value(data,
1377 NCT6775_REG_CRITICAL_ENAB[i]);
1378 data->auto_pwm[i][data->auto_pwm_num] =
1379 (reg & 0x02) ? 0xff : 0x00;
1380 break;
1381 case nct6776:
1382 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1383 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001384 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001385 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001386 case nct6791:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001387 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001388 data->REG_CRITICAL_PWM_ENABLE[i]);
1389 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1390 reg = nct6775_read_value(data,
1391 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001392 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001393 reg = 0xff;
1394 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001395 break;
1396 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001397 }
1398}
1399
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001400static struct nct6775_data *nct6775_update_device(struct device *dev)
1401{
1402 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001403 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001404
1405 mutex_lock(&data->update_lock);
1406
Guenter Roeck6445e662013-04-21 09:13:28 -07001407 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001408 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001409 /* Fan clock dividers */
1410 nct6775_update_fan_div_common(data);
1411
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001412 /* Measured voltages and limits */
1413 for (i = 0; i < data->in_num; i++) {
1414 if (!(data->have_in & (1 << i)))
1415 continue;
1416
1417 data->in[i][0] = nct6775_read_value(data,
1418 data->REG_VIN[i]);
1419 data->in[i][1] = nct6775_read_value(data,
1420 data->REG_IN_MINMAX[0][i]);
1421 data->in[i][2] = nct6775_read_value(data,
1422 data->REG_IN_MINMAX[1][i]);
1423 }
1424
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001425 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001426 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001427 u16 reg;
1428
1429 if (!(data->has_fan & (1 << i)))
1430 continue;
1431
1432 reg = nct6775_read_value(data, data->REG_FAN[i]);
1433 data->rpm[i] = data->fan_from_reg(reg,
1434 data->fan_div[i]);
1435
1436 if (data->has_fan_min & (1 << i))
1437 data->fan_min[i] = nct6775_read_value(data,
1438 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001439 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001440 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1441 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001442
1443 nct6775_select_fan_div(dev, data, i, reg);
1444 }
1445
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001446 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001447 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001448
Guenter Roeckaa136e52012-12-04 03:26:05 -08001449 /* Measured temperatures and limits */
1450 for (i = 0; i < NUM_TEMP; i++) {
1451 if (!(data->have_temp & (1 << i)))
1452 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001453 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001454 if (data->reg_temp[j][i])
1455 data->temp[j][i]
1456 = nct6775_read_temp(data,
1457 data->reg_temp[j][i]);
1458 }
1459 if (!(data->have_temp_fixed & (1 << i)))
1460 continue;
1461 data->temp_offset[i]
1462 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1463 }
1464
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001465 data->alarms = 0;
1466 for (i = 0; i < NUM_REG_ALARM; i++) {
1467 u8 alarm;
1468 if (!data->REG_ALARM[i])
1469 continue;
1470 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1471 data->alarms |= ((u64)alarm) << (i << 3);
1472 }
1473
Guenter Roeck30846992013-06-24 22:21:59 -07001474 data->beeps = 0;
1475 for (i = 0; i < NUM_REG_BEEP; i++) {
1476 u8 beep;
1477 if (!data->REG_BEEP[i])
1478 continue;
1479 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1480 data->beeps |= ((u64)beep) << (i << 3);
1481 }
1482
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001483 data->last_updated = jiffies;
1484 data->valid = true;
1485 }
1486
1487 mutex_unlock(&data->update_lock);
1488 return data;
1489}
1490
1491/*
1492 * Sysfs callback functions
1493 */
1494static ssize_t
1495show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1496{
1497 struct nct6775_data *data = nct6775_update_device(dev);
1498 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1499 int nr = sattr->nr;
1500 int index = sattr->index;
1501 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1502}
1503
1504static ssize_t
1505store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1506 size_t count)
1507{
1508 struct nct6775_data *data = dev_get_drvdata(dev);
1509 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1510 int nr = sattr->nr;
1511 int index = sattr->index;
1512 unsigned long val;
1513 int err = kstrtoul(buf, 10, &val);
1514 if (err < 0)
1515 return err;
1516 mutex_lock(&data->update_lock);
1517 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001518 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001519 data->in[nr][index]);
1520 mutex_unlock(&data->update_lock);
1521 return count;
1522}
1523
1524static ssize_t
1525show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1526{
1527 struct nct6775_data *data = nct6775_update_device(dev);
1528 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1529 int nr = data->ALARM_BITS[sattr->index];
1530 return sprintf(buf, "%u\n",
1531 (unsigned int)((data->alarms >> nr) & 0x01));
1532}
1533
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001534static int find_temp_source(struct nct6775_data *data, int index, int count)
1535{
1536 int source = data->temp_src[index];
1537 int nr;
1538
1539 for (nr = 0; nr < count; nr++) {
1540 int src;
1541
1542 src = nct6775_read_value(data,
1543 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1544 if (src == source)
1545 return nr;
1546 }
1547 return -1;
1548}
1549
1550static ssize_t
1551show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1552{
1553 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1554 struct nct6775_data *data = nct6775_update_device(dev);
1555 unsigned int alarm = 0;
1556 int nr;
1557
1558 /*
1559 * For temperatures, there is no fixed mapping from registers to alarm
1560 * bits. Alarm bits are determined by the temperature source mapping.
1561 */
1562 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1563 if (nr >= 0) {
1564 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
1565 alarm = (data->alarms >> bit) & 0x01;
1566 }
1567 return sprintf(buf, "%u\n", alarm);
1568}
1569
Guenter Roeck30846992013-06-24 22:21:59 -07001570static ssize_t
1571show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1572{
1573 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1574 struct nct6775_data *data = nct6775_update_device(dev);
1575 int nr = data->BEEP_BITS[sattr->index];
1576
1577 return sprintf(buf, "%u\n",
1578 (unsigned int)((data->beeps >> nr) & 0x01));
1579}
1580
1581static ssize_t
1582store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1583 size_t count)
1584{
1585 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1586 struct nct6775_data *data = dev_get_drvdata(dev);
1587 int nr = data->BEEP_BITS[sattr->index];
1588 int regindex = nr >> 3;
1589 unsigned long val;
1590
1591 int err = kstrtoul(buf, 10, &val);
1592 if (err < 0)
1593 return err;
1594 if (val > 1)
1595 return -EINVAL;
1596
1597 mutex_lock(&data->update_lock);
1598 if (val)
1599 data->beeps |= (1ULL << nr);
1600 else
1601 data->beeps &= ~(1ULL << nr);
1602 nct6775_write_value(data, data->REG_BEEP[regindex],
1603 (data->beeps >> (regindex << 3)) & 0xff);
1604 mutex_unlock(&data->update_lock);
1605 return count;
1606}
1607
1608static ssize_t
1609show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1610{
1611 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1612 struct nct6775_data *data = nct6775_update_device(dev);
1613 unsigned int beep = 0;
1614 int nr;
1615
1616 /*
1617 * For temperatures, there is no fixed mapping from registers to beep
1618 * enable bits. Beep enable bits are determined by the temperature
1619 * source mapping.
1620 */
1621 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1622 if (nr >= 0) {
1623 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1624 beep = (data->beeps >> bit) & 0x01;
1625 }
1626 return sprintf(buf, "%u\n", beep);
1627}
1628
1629static ssize_t
1630store_temp_beep(struct device *dev, struct device_attribute *attr,
1631 const char *buf, size_t count)
1632{
1633 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1634 struct nct6775_data *data = dev_get_drvdata(dev);
1635 int nr, bit, regindex;
1636 unsigned long val;
1637
1638 int err = kstrtoul(buf, 10, &val);
1639 if (err < 0)
1640 return err;
1641 if (val > 1)
1642 return -EINVAL;
1643
1644 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1645 if (nr < 0)
1646 return -ENODEV;
1647
1648 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1649 regindex = bit >> 3;
1650
1651 mutex_lock(&data->update_lock);
1652 if (val)
1653 data->beeps |= (1ULL << bit);
1654 else
1655 data->beeps &= ~(1ULL << bit);
1656 nct6775_write_value(data, data->REG_BEEP[regindex],
1657 (data->beeps >> (regindex << 3)) & 0xff);
1658 mutex_unlock(&data->update_lock);
1659
1660 return count;
1661}
1662
Guenter Roeckf73cf632013-03-18 09:22:50 -07001663static umode_t nct6775_in_is_visible(struct kobject *kobj,
1664 struct attribute *attr, int index)
1665{
1666 struct device *dev = container_of(kobj, struct device, kobj);
1667 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001668 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001669
Guenter Roeckf73cf632013-03-18 09:22:50 -07001670 if (!(data->have_in & (1 << in)))
1671 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001672
Guenter Roeckf73cf632013-03-18 09:22:50 -07001673 return attr->mode;
1674}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001675
Guenter Roeckf73cf632013-03-18 09:22:50 -07001676SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1677SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001678SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1679 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001680SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1681 store_in_reg, 0, 1);
1682SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1683 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001684
Guenter Roeckf73cf632013-03-18 09:22:50 -07001685/*
1686 * nct6775_in_is_visible uses the index into the following array
1687 * to determine if attributes should be created or not.
1688 * Any change in order or content must be matched.
1689 */
1690static struct sensor_device_template *nct6775_attributes_in_template[] = {
1691 &sensor_dev_template_in_input,
1692 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001693 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001694 &sensor_dev_template_in_min,
1695 &sensor_dev_template_in_max,
1696 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001697};
1698
Guenter Roeckf73cf632013-03-18 09:22:50 -07001699static struct sensor_template_group nct6775_in_template_group = {
1700 .templates = nct6775_attributes_in_template,
1701 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001702};
1703
1704static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001705show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1706{
1707 struct nct6775_data *data = nct6775_update_device(dev);
1708 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1709 int nr = sattr->index;
1710 return sprintf(buf, "%d\n", data->rpm[nr]);
1711}
1712
1713static ssize_t
1714show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1715{
1716 struct nct6775_data *data = nct6775_update_device(dev);
1717 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1718 int nr = sattr->index;
1719 return sprintf(buf, "%d\n",
1720 data->fan_from_reg_min(data->fan_min[nr],
1721 data->fan_div[nr]));
1722}
1723
1724static ssize_t
1725show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1726{
1727 struct nct6775_data *data = nct6775_update_device(dev);
1728 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1729 int nr = sattr->index;
1730 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1731}
1732
1733static ssize_t
1734store_fan_min(struct device *dev, struct device_attribute *attr,
1735 const char *buf, size_t count)
1736{
1737 struct nct6775_data *data = dev_get_drvdata(dev);
1738 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1739 int nr = sattr->index;
1740 unsigned long val;
1741 int err;
1742 unsigned int reg;
1743 u8 new_div;
1744
1745 err = kstrtoul(buf, 10, &val);
1746 if (err < 0)
1747 return err;
1748
1749 mutex_lock(&data->update_lock);
1750 if (!data->has_fan_div) {
1751 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1752 if (!val) {
1753 val = 0xff1f;
1754 } else {
1755 if (val > 1350000U)
1756 val = 135000U;
1757 val = 1350000U / val;
1758 val = (val & 0x1f) | ((val << 3) & 0xff00);
1759 }
1760 data->fan_min[nr] = val;
1761 goto write_min; /* Leave fan divider alone */
1762 }
1763 if (!val) {
1764 /* No min limit, alarm disabled */
1765 data->fan_min[nr] = 255;
1766 new_div = data->fan_div[nr]; /* No change */
1767 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1768 goto write_div;
1769 }
1770 reg = 1350000U / val;
1771 if (reg >= 128 * 255) {
1772 /*
1773 * Speed below this value cannot possibly be represented,
1774 * even with the highest divider (128)
1775 */
1776 data->fan_min[nr] = 254;
1777 new_div = 7; /* 128 == (1 << 7) */
1778 dev_warn(dev,
1779 "fan%u low limit %lu below minimum %u, set to minimum\n",
1780 nr + 1, val, data->fan_from_reg_min(254, 7));
1781 } else if (!reg) {
1782 /*
1783 * Speed above this value cannot possibly be represented,
1784 * even with the lowest divider (1)
1785 */
1786 data->fan_min[nr] = 1;
1787 new_div = 0; /* 1 == (1 << 0) */
1788 dev_warn(dev,
1789 "fan%u low limit %lu above maximum %u, set to maximum\n",
1790 nr + 1, val, data->fan_from_reg_min(1, 0));
1791 } else {
1792 /*
1793 * Automatically pick the best divider, i.e. the one such
1794 * that the min limit will correspond to a register value
1795 * in the 96..192 range
1796 */
1797 new_div = 0;
1798 while (reg > 192 && new_div < 7) {
1799 reg >>= 1;
1800 new_div++;
1801 }
1802 data->fan_min[nr] = reg;
1803 }
1804
1805write_div:
1806 /*
1807 * Write both the fan clock divider (if it changed) and the new
1808 * fan min (unconditionally)
1809 */
1810 if (new_div != data->fan_div[nr]) {
1811 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1812 nr + 1, div_from_reg(data->fan_div[nr]),
1813 div_from_reg(new_div));
1814 data->fan_div[nr] = new_div;
1815 nct6775_write_fan_div_common(data, nr);
1816 /* Give the chip time to sample a new speed value */
1817 data->last_updated = jiffies;
1818 }
1819
1820write_min:
1821 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1822 mutex_unlock(&data->update_lock);
1823
1824 return count;
1825}
1826
Guenter Roeck5c25d952012-12-11 07:29:06 -08001827static ssize_t
1828show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1829{
1830 struct nct6775_data *data = nct6775_update_device(dev);
1831 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1832 int p = data->fan_pulses[sattr->index];
1833
1834 return sprintf(buf, "%d\n", p ? : 4);
1835}
1836
1837static ssize_t
1838store_fan_pulses(struct device *dev, struct device_attribute *attr,
1839 const char *buf, size_t count)
1840{
1841 struct nct6775_data *data = dev_get_drvdata(dev);
1842 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1843 int nr = sattr->index;
1844 unsigned long val;
1845 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001846 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001847
1848 err = kstrtoul(buf, 10, &val);
1849 if (err < 0)
1850 return err;
1851
1852 if (val > 4)
1853 return -EINVAL;
1854
1855 mutex_lock(&data->update_lock);
1856 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001857 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1858 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1859 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1860 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001861 mutex_unlock(&data->update_lock);
1862
1863 return count;
1864}
1865
Guenter Roeckf73cf632013-03-18 09:22:50 -07001866static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1867 struct attribute *attr, int index)
1868{
1869 struct device *dev = container_of(kobj, struct device, kobj);
1870 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001871 int fan = index / 6; /* fan index */
1872 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001873
1874 if (!(data->has_fan & (1 << fan)))
1875 return 0;
1876
1877 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1878 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001879 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001880 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001881 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1882 return 0;
1883 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001884 return 0;
1885
1886 return attr->mode;
1887}
1888
1889SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1890SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1891 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001892SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1893 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001894SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1895 store_fan_pulses, 0);
1896SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1897 store_fan_min, 0);
1898SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1899
1900/*
1901 * nct6775_fan_is_visible uses the index into the following array
1902 * to determine if attributes should be created or not.
1903 * Any change in order or content must be matched.
1904 */
1905static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1906 &sensor_dev_template_fan_input,
1907 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001908 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001909 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001910 &sensor_dev_template_fan_min, /* 4 */
1911 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001912 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001913};
1914
Guenter Roeckf73cf632013-03-18 09:22:50 -07001915static struct sensor_template_group nct6775_fan_template_group = {
1916 .templates = nct6775_attributes_fan_template,
1917 .is_visible = nct6775_fan_is_visible,
1918 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001919};
1920
1921static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001922show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1923{
1924 struct nct6775_data *data = nct6775_update_device(dev);
1925 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1926 int nr = sattr->index;
1927 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1928}
1929
1930static ssize_t
1931show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1932{
1933 struct nct6775_data *data = nct6775_update_device(dev);
1934 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1935 int nr = sattr->nr;
1936 int index = sattr->index;
1937
1938 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1939}
1940
1941static ssize_t
1942store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1943 size_t count)
1944{
1945 struct nct6775_data *data = dev_get_drvdata(dev);
1946 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1947 int nr = sattr->nr;
1948 int index = sattr->index;
1949 int err;
1950 long val;
1951
1952 err = kstrtol(buf, 10, &val);
1953 if (err < 0)
1954 return err;
1955
1956 mutex_lock(&data->update_lock);
1957 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
1958 nct6775_write_temp(data, data->reg_temp[index][nr],
1959 data->temp[index][nr]);
1960 mutex_unlock(&data->update_lock);
1961 return count;
1962}
1963
1964static ssize_t
1965show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
1966{
1967 struct nct6775_data *data = nct6775_update_device(dev);
1968 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1969
1970 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
1971}
1972
1973static ssize_t
1974store_temp_offset(struct device *dev, struct device_attribute *attr,
1975 const char *buf, size_t count)
1976{
1977 struct nct6775_data *data = dev_get_drvdata(dev);
1978 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1979 int nr = sattr->index;
1980 long val;
1981 int err;
1982
1983 err = kstrtol(buf, 10, &val);
1984 if (err < 0)
1985 return err;
1986
1987 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
1988
1989 mutex_lock(&data->update_lock);
1990 data->temp_offset[nr] = val;
1991 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
1992 mutex_unlock(&data->update_lock);
1993
1994 return count;
1995}
1996
1997static ssize_t
1998show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
1999{
2000 struct nct6775_data *data = nct6775_update_device(dev);
2001 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2002 int nr = sattr->index;
2003 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2004}
2005
2006static ssize_t
2007store_temp_type(struct device *dev, struct device_attribute *attr,
2008 const char *buf, size_t count)
2009{
2010 struct nct6775_data *data = nct6775_update_device(dev);
2011 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2012 int nr = sattr->index;
2013 unsigned long val;
2014 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002015 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002016
2017 err = kstrtoul(buf, 10, &val);
2018 if (err < 0)
2019 return err;
2020
2021 if (val != 1 && val != 3 && val != 4)
2022 return -EINVAL;
2023
2024 mutex_lock(&data->update_lock);
2025
2026 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002027 vbit = 0x02 << nr;
2028 dbit = data->DIODE_MASK << nr;
2029 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2030 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002031 switch (val) {
2032 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002033 vbat |= vbit;
2034 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002035 break;
2036 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002037 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002038 break;
2039 case 4: /* thermistor */
2040 break;
2041 }
2042 nct6775_write_value(data, data->REG_VBAT, vbat);
2043 nct6775_write_value(data, data->REG_DIODE, diode);
2044
2045 mutex_unlock(&data->update_lock);
2046 return count;
2047}
2048
Guenter Roeckf73cf632013-03-18 09:22:50 -07002049static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2050 struct attribute *attr, int index)
2051{
2052 struct device *dev = container_of(kobj, struct device, kobj);
2053 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002054 int temp = index / 10; /* temp index */
2055 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002056
2057 if (!(data->have_temp & (1 << temp)))
2058 return 0;
2059
2060 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2061 return 0; /* alarm */
2062
Guenter Roeck30846992013-06-24 22:21:59 -07002063 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2064 return 0; /* beep */
2065
2066 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002067 return 0;
2068
Guenter Roeck30846992013-06-24 22:21:59 -07002069 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002070 return 0;
2071
Guenter Roeck30846992013-06-24 22:21:59 -07002072 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002073 return 0;
2074
Guenter Roeck30846992013-06-24 22:21:59 -07002075 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002076 return 0;
2077
2078 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002079 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002080 return 0;
2081
2082 return attr->mode;
2083}
2084
2085SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2086SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2087SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2088 store_temp, 0, 1);
2089SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2090 show_temp, store_temp, 0, 2);
2091SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2092 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002093SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2094 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002095SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2096 show_temp_offset, store_temp_offset, 0);
2097SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2098 store_temp_type, 0);
2099SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002100SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2101 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002102
2103/*
2104 * nct6775_temp_is_visible uses the index into the following array
2105 * to determine if attributes should be created or not.
2106 * Any change in order or content must be matched.
2107 */
2108static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2109 &sensor_dev_template_temp_input,
2110 &sensor_dev_template_temp_label,
2111 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002112 &sensor_dev_template_temp_beep, /* 3 */
2113 &sensor_dev_template_temp_max, /* 4 */
2114 &sensor_dev_template_temp_max_hyst, /* 5 */
2115 &sensor_dev_template_temp_crit, /* 6 */
2116 &sensor_dev_template_temp_lcrit, /* 7 */
2117 &sensor_dev_template_temp_offset, /* 8 */
2118 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002119 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002120};
2121
Guenter Roeckf73cf632013-03-18 09:22:50 -07002122static struct sensor_template_group nct6775_temp_template_group = {
2123 .templates = nct6775_attributes_temp_template,
2124 .is_visible = nct6775_temp_is_visible,
2125 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002126};
2127
Guenter Roeckaa136e52012-12-04 03:26:05 -08002128static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002129show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2130{
2131 struct nct6775_data *data = nct6775_update_device(dev);
2132 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2133
2134 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2135}
2136
2137static ssize_t
2138store_pwm_mode(struct device *dev, struct device_attribute *attr,
2139 const char *buf, size_t count)
2140{
2141 struct nct6775_data *data = dev_get_drvdata(dev);
2142 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2143 int nr = sattr->index;
2144 unsigned long val;
2145 int err;
2146 u8 reg;
2147
2148 err = kstrtoul(buf, 10, &val);
2149 if (err < 0)
2150 return err;
2151
2152 if (val > 1)
2153 return -EINVAL;
2154
2155 /* Setting DC mode is not supported for all chips/channels */
2156 if (data->REG_PWM_MODE[nr] == 0) {
2157 if (val)
2158 return -EINVAL;
2159 return count;
2160 }
2161
2162 mutex_lock(&data->update_lock);
2163 data->pwm_mode[nr] = val;
2164 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2165 reg &= ~data->PWM_MODE_MASK[nr];
2166 if (val)
2167 reg |= data->PWM_MODE_MASK[nr];
2168 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2169 mutex_unlock(&data->update_lock);
2170 return count;
2171}
2172
2173static ssize_t
2174show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2175{
2176 struct nct6775_data *data = nct6775_update_device(dev);
2177 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2178 int nr = sattr->nr;
2179 int index = sattr->index;
2180 int pwm;
2181
2182 /*
2183 * For automatic fan control modes, show current pwm readings.
2184 * Otherwise, show the configured value.
2185 */
2186 if (index == 0 && data->pwm_enable[nr] > manual)
2187 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2188 else
2189 pwm = data->pwm[index][nr];
2190
2191 return sprintf(buf, "%d\n", pwm);
2192}
2193
2194static ssize_t
2195store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2196 size_t count)
2197{
2198 struct nct6775_data *data = dev_get_drvdata(dev);
2199 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2200 int nr = sattr->nr;
2201 int index = sattr->index;
2202 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002203 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2204 int maxval[7]
2205 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002206 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002207 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002208
2209 err = kstrtoul(buf, 10, &val);
2210 if (err < 0)
2211 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002212 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002213
2214 mutex_lock(&data->update_lock);
2215 data->pwm[index][nr] = val;
2216 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002217 if (index == 2) { /* floor: disable if val == 0 */
2218 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2219 reg &= 0x7f;
2220 if (val)
2221 reg |= 0x80;
2222 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2223 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002224 mutex_unlock(&data->update_lock);
2225 return count;
2226}
2227
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002228/* Returns 0 if OK, -EINVAL otherwise */
2229static int check_trip_points(struct nct6775_data *data, int nr)
2230{
2231 int i;
2232
2233 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2234 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2235 return -EINVAL;
2236 }
2237 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2238 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2239 return -EINVAL;
2240 }
2241 /* validate critical temperature and pwm if enabled (pwm > 0) */
2242 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2243 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2244 data->auto_temp[nr][data->auto_pwm_num] ||
2245 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2246 data->auto_pwm[nr][data->auto_pwm_num])
2247 return -EINVAL;
2248 }
2249 return 0;
2250}
2251
2252static void pwm_update_registers(struct nct6775_data *data, int nr)
2253{
2254 u8 reg;
2255
2256 switch (data->pwm_enable[nr]) {
2257 case off:
2258 case manual:
2259 break;
2260 case speed_cruise:
2261 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2262 reg = (reg & ~data->tolerance_mask) |
2263 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2264 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2265 nct6775_write_value(data, data->REG_TARGET[nr],
2266 data->target_speed[nr] & 0xff);
2267 if (data->REG_TOLERANCE_H) {
2268 reg = (data->target_speed[nr] >> 8) & 0x0f;
2269 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2270 nct6775_write_value(data,
2271 data->REG_TOLERANCE_H[nr],
2272 reg);
2273 }
2274 break;
2275 case thermal_cruise:
2276 nct6775_write_value(data, data->REG_TARGET[nr],
2277 data->target_temp[nr]);
2278 /* intentional */
2279 default:
2280 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2281 reg = (reg & ~data->tolerance_mask) |
2282 data->temp_tolerance[0][nr];
2283 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2284 break;
2285 }
2286}
2287
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002288static ssize_t
2289show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2290{
2291 struct nct6775_data *data = nct6775_update_device(dev);
2292 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2293
2294 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2295}
2296
2297static ssize_t
2298store_pwm_enable(struct device *dev, struct device_attribute *attr,
2299 const char *buf, size_t count)
2300{
2301 struct nct6775_data *data = dev_get_drvdata(dev);
2302 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2303 int nr = sattr->index;
2304 unsigned long val;
2305 int err;
2306 u16 reg;
2307
2308 err = kstrtoul(buf, 10, &val);
2309 if (err < 0)
2310 return err;
2311
2312 if (val > sf4)
2313 return -EINVAL;
2314
2315 if (val == sf3 && data->kind != nct6775)
2316 return -EINVAL;
2317
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002318 if (val == sf4 && check_trip_points(data, nr)) {
2319 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2320 dev_err(dev, "Adjust trip points and try again\n");
2321 return -EINVAL;
2322 }
2323
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002324 mutex_lock(&data->update_lock);
2325 data->pwm_enable[nr] = val;
2326 if (val == off) {
2327 /*
2328 * turn off pwm control: select manual mode, set pwm to maximum
2329 */
2330 data->pwm[0][nr] = 255;
2331 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2332 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002333 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002334 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2335 reg &= 0x0f;
2336 reg |= pwm_enable_to_reg(val) << 4;
2337 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2338 mutex_unlock(&data->update_lock);
2339 return count;
2340}
2341
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002342static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002343show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002344{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002345 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002346
2347 for (i = 0; i < NUM_TEMP; i++) {
2348 if (!(data->have_temp & (1 << i)))
2349 continue;
2350 if (src == data->temp_src[i]) {
2351 sel = i + 1;
2352 break;
2353 }
2354 }
2355
2356 return sprintf(buf, "%d\n", sel);
2357}
2358
2359static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002360show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2361{
2362 struct nct6775_data *data = nct6775_update_device(dev);
2363 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2364 int index = sattr->index;
2365
2366 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2367}
2368
2369static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002370store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2371 const char *buf, size_t count)
2372{
2373 struct nct6775_data *data = nct6775_update_device(dev);
2374 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2375 int nr = sattr->index;
2376 unsigned long val;
2377 int err, reg, src;
2378
2379 err = kstrtoul(buf, 10, &val);
2380 if (err < 0)
2381 return err;
2382 if (val == 0 || val > NUM_TEMP)
2383 return -EINVAL;
2384 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2385 return -EINVAL;
2386
2387 mutex_lock(&data->update_lock);
2388 src = data->temp_src[val - 1];
2389 data->pwm_temp_sel[nr] = src;
2390 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2391 reg &= 0xe0;
2392 reg |= src;
2393 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2394 mutex_unlock(&data->update_lock);
2395
2396 return count;
2397}
2398
2399static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002400show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2401 char *buf)
2402{
2403 struct nct6775_data *data = nct6775_update_device(dev);
2404 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2405 int index = sattr->index;
2406
2407 return show_pwm_temp_sel_common(data, buf,
2408 data->pwm_weight_temp_sel[index]);
2409}
2410
2411static ssize_t
2412store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2413 const char *buf, size_t count)
2414{
2415 struct nct6775_data *data = nct6775_update_device(dev);
2416 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2417 int nr = sattr->index;
2418 unsigned long val;
2419 int err, reg, src;
2420
2421 err = kstrtoul(buf, 10, &val);
2422 if (err < 0)
2423 return err;
2424 if (val > NUM_TEMP)
2425 return -EINVAL;
2426 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2427 !data->temp_src[val - 1]))
2428 return -EINVAL;
2429
2430 mutex_lock(&data->update_lock);
2431 if (val) {
2432 src = data->temp_src[val - 1];
2433 data->pwm_weight_temp_sel[nr] = src;
2434 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2435 reg &= 0xe0;
2436 reg |= (src | 0x80);
2437 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2438 } else {
2439 data->pwm_weight_temp_sel[nr] = 0;
2440 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2441 reg &= 0x7f;
2442 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2443 }
2444 mutex_unlock(&data->update_lock);
2445
2446 return count;
2447}
2448
2449static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002450show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2451{
2452 struct nct6775_data *data = nct6775_update_device(dev);
2453 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2454
2455 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2456}
2457
2458static ssize_t
2459store_target_temp(struct device *dev, struct device_attribute *attr,
2460 const char *buf, size_t count)
2461{
2462 struct nct6775_data *data = dev_get_drvdata(dev);
2463 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2464 int nr = sattr->index;
2465 unsigned long val;
2466 int err;
2467
2468 err = kstrtoul(buf, 10, &val);
2469 if (err < 0)
2470 return err;
2471
2472 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2473 data->target_temp_mask);
2474
2475 mutex_lock(&data->update_lock);
2476 data->target_temp[nr] = val;
2477 pwm_update_registers(data, nr);
2478 mutex_unlock(&data->update_lock);
2479 return count;
2480}
2481
2482static ssize_t
2483show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2484{
2485 struct nct6775_data *data = nct6775_update_device(dev);
2486 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2487 int nr = sattr->index;
2488
2489 return sprintf(buf, "%d\n",
2490 fan_from_reg16(data->target_speed[nr],
2491 data->fan_div[nr]));
2492}
2493
2494static ssize_t
2495store_target_speed(struct device *dev, struct device_attribute *attr,
2496 const char *buf, size_t count)
2497{
2498 struct nct6775_data *data = dev_get_drvdata(dev);
2499 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2500 int nr = sattr->index;
2501 unsigned long val;
2502 int err;
2503 u16 speed;
2504
2505 err = kstrtoul(buf, 10, &val);
2506 if (err < 0)
2507 return err;
2508
2509 val = clamp_val(val, 0, 1350000U);
2510 speed = fan_to_reg(val, data->fan_div[nr]);
2511
2512 mutex_lock(&data->update_lock);
2513 data->target_speed[nr] = speed;
2514 pwm_update_registers(data, nr);
2515 mutex_unlock(&data->update_lock);
2516 return count;
2517}
2518
2519static ssize_t
2520show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2521 char *buf)
2522{
2523 struct nct6775_data *data = nct6775_update_device(dev);
2524 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2525 int nr = sattr->nr;
2526 int index = sattr->index;
2527
2528 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2529}
2530
2531static ssize_t
2532store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2533 const char *buf, size_t count)
2534{
2535 struct nct6775_data *data = dev_get_drvdata(dev);
2536 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2537 int nr = sattr->nr;
2538 int index = sattr->index;
2539 unsigned long val;
2540 int err;
2541
2542 err = kstrtoul(buf, 10, &val);
2543 if (err < 0)
2544 return err;
2545
2546 /* Limit tolerance as needed */
2547 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2548
2549 mutex_lock(&data->update_lock);
2550 data->temp_tolerance[index][nr] = val;
2551 if (index)
2552 pwm_update_registers(data, nr);
2553 else
2554 nct6775_write_value(data,
2555 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2556 val);
2557 mutex_unlock(&data->update_lock);
2558 return count;
2559}
2560
2561/*
2562 * Fan speed tolerance is a tricky beast, since the associated register is
2563 * a tick counter, but the value is reported and configured as rpm.
2564 * Compute resulting low and high rpm values and report the difference.
2565 */
2566static ssize_t
2567show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2568 char *buf)
2569{
2570 struct nct6775_data *data = nct6775_update_device(dev);
2571 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2572 int nr = sattr->index;
2573 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2574 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2575 int tolerance;
2576
2577 if (low <= 0)
2578 low = 1;
2579 if (high > 0xffff)
2580 high = 0xffff;
2581 if (high < low)
2582 high = low;
2583
2584 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2585 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2586
2587 return sprintf(buf, "%d\n", tolerance);
2588}
2589
2590static ssize_t
2591store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2592 const char *buf, size_t count)
2593{
2594 struct nct6775_data *data = dev_get_drvdata(dev);
2595 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2596 int nr = sattr->index;
2597 unsigned long val;
2598 int err;
2599 int low, high;
2600
2601 err = kstrtoul(buf, 10, &val);
2602 if (err < 0)
2603 return err;
2604
2605 high = fan_from_reg16(data->target_speed[nr],
2606 data->fan_div[nr]) + val;
2607 low = fan_from_reg16(data->target_speed[nr],
2608 data->fan_div[nr]) - val;
2609 if (low <= 0)
2610 low = 1;
2611 if (high < low)
2612 high = low;
2613
2614 val = (fan_to_reg(low, data->fan_div[nr]) -
2615 fan_to_reg(high, data->fan_div[nr])) / 2;
2616
2617 /* Limit tolerance as needed */
2618 val = clamp_val(val, 0, data->speed_tolerance_limit);
2619
2620 mutex_lock(&data->update_lock);
2621 data->target_speed_tolerance[nr] = val;
2622 pwm_update_registers(data, nr);
2623 mutex_unlock(&data->update_lock);
2624 return count;
2625}
2626
Guenter Roeckf73cf632013-03-18 09:22:50 -07002627SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2628SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2629 store_pwm_mode, 0);
2630SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2631 store_pwm_enable, 0);
2632SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2633 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2634SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2635 show_target_temp, store_target_temp, 0);
2636SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2637 show_target_speed, store_target_speed, 0);
2638SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2639 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002640
2641/* Smart Fan registers */
2642
2643static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002644show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2645{
2646 struct nct6775_data *data = nct6775_update_device(dev);
2647 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2648 int nr = sattr->nr;
2649 int index = sattr->index;
2650
2651 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2652}
2653
2654static ssize_t
2655store_weight_temp(struct device *dev, struct device_attribute *attr,
2656 const char *buf, size_t count)
2657{
2658 struct nct6775_data *data = dev_get_drvdata(dev);
2659 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2660 int nr = sattr->nr;
2661 int index = sattr->index;
2662 unsigned long val;
2663 int err;
2664
2665 err = kstrtoul(buf, 10, &val);
2666 if (err < 0)
2667 return err;
2668
2669 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2670
2671 mutex_lock(&data->update_lock);
2672 data->weight_temp[index][nr] = val;
2673 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2674 mutex_unlock(&data->update_lock);
2675 return count;
2676}
2677
Guenter Roeckf73cf632013-03-18 09:22:50 -07002678SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2679 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2680SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2681 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2682SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2683 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2684SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2685 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2686SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2687 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2688SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2689 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002690
2691static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002692show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2693{
2694 struct nct6775_data *data = nct6775_update_device(dev);
2695 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2696 int nr = sattr->nr;
2697 int index = sattr->index;
2698
2699 return sprintf(buf, "%d\n",
2700 step_time_from_reg(data->fan_time[index][nr],
2701 data->pwm_mode[nr]));
2702}
2703
2704static ssize_t
2705store_fan_time(struct device *dev, struct device_attribute *attr,
2706 const char *buf, size_t count)
2707{
2708 struct nct6775_data *data = dev_get_drvdata(dev);
2709 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2710 int nr = sattr->nr;
2711 int index = sattr->index;
2712 unsigned long val;
2713 int err;
2714
2715 err = kstrtoul(buf, 10, &val);
2716 if (err < 0)
2717 return err;
2718
2719 val = step_time_to_reg(val, data->pwm_mode[nr]);
2720 mutex_lock(&data->update_lock);
2721 data->fan_time[index][nr] = val;
2722 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2723 mutex_unlock(&data->update_lock);
2724 return count;
2725}
2726
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002727static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002728show_name(struct device *dev, struct device_attribute *attr, char *buf)
2729{
2730 struct nct6775_data *data = dev_get_drvdata(dev);
2731
2732 return sprintf(buf, "%s\n", data->name);
2733}
2734
2735static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
2736
2737static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002738show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2739{
2740 struct nct6775_data *data = nct6775_update_device(dev);
2741 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2742
2743 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2744}
2745
2746static ssize_t
2747store_auto_pwm(struct device *dev, struct device_attribute *attr,
2748 const char *buf, size_t count)
2749{
2750 struct nct6775_data *data = dev_get_drvdata(dev);
2751 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2752 int nr = sattr->nr;
2753 int point = sattr->index;
2754 unsigned long val;
2755 int err;
2756 u8 reg;
2757
2758 err = kstrtoul(buf, 10, &val);
2759 if (err < 0)
2760 return err;
2761 if (val > 255)
2762 return -EINVAL;
2763
2764 if (point == data->auto_pwm_num) {
2765 if (data->kind != nct6775 && !val)
2766 return -EINVAL;
2767 if (data->kind != nct6779 && val)
2768 val = 0xff;
2769 }
2770
2771 mutex_lock(&data->update_lock);
2772 data->auto_pwm[nr][point] = val;
2773 if (point < data->auto_pwm_num) {
2774 nct6775_write_value(data,
2775 NCT6775_AUTO_PWM(data, nr, point),
2776 data->auto_pwm[nr][point]);
2777 } else {
2778 switch (data->kind) {
2779 case nct6775:
2780 /* disable if needed (pwm == 0) */
2781 reg = nct6775_read_value(data,
2782 NCT6775_REG_CRITICAL_ENAB[nr]);
2783 if (val)
2784 reg |= 0x02;
2785 else
2786 reg &= ~0x02;
2787 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2788 reg);
2789 break;
2790 case nct6776:
2791 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002792 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002793 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002794 case nct6791:
Guenter Roeck6c009502012-07-01 08:23:15 -07002795 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002796 val);
2797 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002798 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002799 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002800 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002801 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002802 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002803 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002804 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002805 reg);
2806 break;
2807 }
2808 }
2809 mutex_unlock(&data->update_lock);
2810 return count;
2811}
2812
2813static ssize_t
2814show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2815{
2816 struct nct6775_data *data = nct6775_update_device(dev);
2817 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2818 int nr = sattr->nr;
2819 int point = sattr->index;
2820
2821 /*
2822 * We don't know for sure if the temperature is signed or unsigned.
2823 * Assume it is unsigned.
2824 */
2825 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2826}
2827
2828static ssize_t
2829store_auto_temp(struct device *dev, struct device_attribute *attr,
2830 const char *buf, size_t count)
2831{
2832 struct nct6775_data *data = dev_get_drvdata(dev);
2833 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2834 int nr = sattr->nr;
2835 int point = sattr->index;
2836 unsigned long val;
2837 int err;
2838
2839 err = kstrtoul(buf, 10, &val);
2840 if (err)
2841 return err;
2842 if (val > 255000)
2843 return -EINVAL;
2844
2845 mutex_lock(&data->update_lock);
2846 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2847 if (point < data->auto_pwm_num) {
2848 nct6775_write_value(data,
2849 NCT6775_AUTO_TEMP(data, nr, point),
2850 data->auto_temp[nr][point]);
2851 } else {
2852 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2853 data->auto_temp[nr][point]);
2854 }
2855 mutex_unlock(&data->update_lock);
2856 return count;
2857}
2858
Guenter Roeckf73cf632013-03-18 09:22:50 -07002859static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2860 struct attribute *attr, int index)
2861{
2862 struct device *dev = container_of(kobj, struct device, kobj);
2863 struct nct6775_data *data = dev_get_drvdata(dev);
2864 int pwm = index / 36; /* pwm index */
2865 int nr = index % 36; /* attribute index */
2866
2867 if (!(data->has_pwm & (1 << pwm)))
2868 return 0;
2869
2870 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2871 return 0;
2872 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2873 return 0;
2874 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2875 return 0;
2876
2877 if (nr >= 22 && nr <= 35) { /* auto point */
2878 int api = (nr - 22) / 2; /* auto point index */
2879
2880 if (api > data->auto_pwm_num)
2881 return 0;
2882 }
2883 return attr->mode;
2884}
2885
2886SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2887 show_fan_time, store_fan_time, 0, 0);
2888SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2889 show_fan_time, store_fan_time, 0, 1);
2890SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2891 show_fan_time, store_fan_time, 0, 2);
2892SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2893 store_pwm, 0, 1);
2894SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2895 store_pwm, 0, 2);
2896SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2897 show_temp_tolerance, store_temp_tolerance, 0, 0);
2898SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2899 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2900 0, 1);
2901
2902SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2903 0, 3);
2904
2905SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2906 store_pwm, 0, 4);
2907
2908SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2909 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2910SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2911 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2912
2913SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2914 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2915SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2916 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2917
2918SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2919 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2920SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2921 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2922
2923SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2924 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2925SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2926 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2927
2928SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2929 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2930SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2931 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2932
2933SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2934 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2935SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2936 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2937
2938SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2939 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2940SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2941 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2942
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002943/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002944 * nct6775_pwm_is_visible uses the index into the following array
2945 * to determine if attributes should be created or not.
2946 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002947 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002948static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2949 &sensor_dev_template_pwm,
2950 &sensor_dev_template_pwm_mode,
2951 &sensor_dev_template_pwm_enable,
2952 &sensor_dev_template_pwm_temp_sel,
2953 &sensor_dev_template_pwm_temp_tolerance,
2954 &sensor_dev_template_pwm_crit_temp_tolerance,
2955 &sensor_dev_template_pwm_target_temp,
2956 &sensor_dev_template_fan_target,
2957 &sensor_dev_template_fan_tolerance,
2958 &sensor_dev_template_pwm_stop_time,
2959 &sensor_dev_template_pwm_step_up_time,
2960 &sensor_dev_template_pwm_step_down_time,
2961 &sensor_dev_template_pwm_start,
2962 &sensor_dev_template_pwm_floor,
2963 &sensor_dev_template_pwm_weight_temp_sel,
2964 &sensor_dev_template_pwm_weight_temp_step,
2965 &sensor_dev_template_pwm_weight_temp_step_tol,
2966 &sensor_dev_template_pwm_weight_temp_step_base,
2967 &sensor_dev_template_pwm_weight_duty_step,
2968 &sensor_dev_template_pwm_max, /* 19 */
2969 &sensor_dev_template_pwm_step, /* 20 */
2970 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
2971 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
2972 &sensor_dev_template_pwm_auto_point1_temp,
2973 &sensor_dev_template_pwm_auto_point2_pwm,
2974 &sensor_dev_template_pwm_auto_point2_temp,
2975 &sensor_dev_template_pwm_auto_point3_pwm,
2976 &sensor_dev_template_pwm_auto_point3_temp,
2977 &sensor_dev_template_pwm_auto_point4_pwm,
2978 &sensor_dev_template_pwm_auto_point4_temp,
2979 &sensor_dev_template_pwm_auto_point5_pwm,
2980 &sensor_dev_template_pwm_auto_point5_temp,
2981 &sensor_dev_template_pwm_auto_point6_pwm,
2982 &sensor_dev_template_pwm_auto_point6_temp,
2983 &sensor_dev_template_pwm_auto_point7_pwm,
2984 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002985
Guenter Roeckf73cf632013-03-18 09:22:50 -07002986 NULL
2987};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002988
Guenter Roeckf73cf632013-03-18 09:22:50 -07002989static struct sensor_template_group nct6775_pwm_template_group = {
2990 .templates = nct6775_attributes_pwm_template,
2991 .is_visible = nct6775_pwm_is_visible,
2992 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002993};
2994
2995static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002996show_vid(struct device *dev, struct device_attribute *attr, char *buf)
2997{
2998 struct nct6775_data *data = dev_get_drvdata(dev);
2999 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3000}
3001
3002static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3003
Guenter Roecka6bd5872012-12-04 03:13:34 -08003004/* Case open detection */
3005
3006static ssize_t
3007clear_caseopen(struct device *dev, struct device_attribute *attr,
3008 const char *buf, size_t count)
3009{
3010 struct nct6775_data *data = dev_get_drvdata(dev);
3011 struct nct6775_sio_data *sio_data = dev->platform_data;
3012 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3013 unsigned long val;
3014 u8 reg;
3015 int ret;
3016
3017 if (kstrtoul(buf, 10, &val) || val != 0)
3018 return -EINVAL;
3019
3020 mutex_lock(&data->update_lock);
3021
3022 /*
3023 * Use CR registers to clear caseopen status.
3024 * The CR registers are the same for all chips, and not all chips
3025 * support clearing the caseopen status through "regular" registers.
3026 */
3027 ret = superio_enter(sio_data->sioreg);
3028 if (ret) {
3029 count = ret;
3030 goto error;
3031 }
3032
3033 superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
3034 reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
3035 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
3036 superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3037 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
3038 superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3039 superio_exit(sio_data->sioreg);
3040
3041 data->valid = false; /* Force cache refresh */
3042error:
3043 mutex_unlock(&data->update_lock);
3044 return count;
3045}
3046
Guenter Roeckf73cf632013-03-18 09:22:50 -07003047static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3048 clear_caseopen, INTRUSION_ALARM_BASE);
3049static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3050 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003051static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3052 store_beep, INTRUSION_ALARM_BASE);
3053static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3054 store_beep, INTRUSION_ALARM_BASE + 1);
3055static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3056 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003057
3058static umode_t nct6775_other_is_visible(struct kobject *kobj,
3059 struct attribute *attr, int index)
3060{
3061 struct device *dev = container_of(kobj, struct device, kobj);
3062 struct nct6775_data *data = dev_get_drvdata(dev);
3063
3064 if (index == 1 && !data->have_vid)
3065 return 0;
3066
3067 if (index == 2 || index == 3) {
3068 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0)
3069 return 0;
3070 }
3071
Guenter Roeck30846992013-06-24 22:21:59 -07003072 if (index == 4 || index == 5) {
3073 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0)
3074 return 0;
3075 }
3076
Guenter Roeckf73cf632013-03-18 09:22:50 -07003077 return attr->mode;
3078}
3079
3080/*
3081 * nct6775_other_is_visible uses the index into the following array
3082 * to determine if attributes should be created or not.
3083 * Any change in order or content must be matched.
3084 */
3085static struct attribute *nct6775_attributes_other[] = {
3086 &dev_attr_name.attr,
3087 &dev_attr_cpu0_vid.attr, /* 1 */
3088 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 2 */
3089 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 3 */
Guenter Roeck30846992013-06-24 22:21:59 -07003090 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 4 */
3091 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 5 */
3092 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 6 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003093
3094 NULL
3095};
3096
3097static const struct attribute_group nct6775_group_other = {
3098 .attrs = nct6775_attributes_other,
3099 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003100};
3101
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003102/*
3103 * Driver and device management
3104 */
3105
3106static void nct6775_device_remove_files(struct device *dev)
3107{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003108 struct nct6775_data *data = dev_get_drvdata(dev);
3109
Guenter Roeckf73cf632013-03-18 09:22:50 -07003110 if (data->group_pwm)
3111 sysfs_remove_group(&dev->kobj, data->group_pwm);
3112 if (data->group_in)
3113 sysfs_remove_group(&dev->kobj, data->group_in);
3114 if (data->group_fan)
3115 sysfs_remove_group(&dev->kobj, data->group_fan);
3116 if (data->group_temp)
3117 sysfs_remove_group(&dev->kobj, data->group_temp);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003118
Guenter Roeckf73cf632013-03-18 09:22:50 -07003119 sysfs_remove_group(&dev->kobj, &nct6775_group_other);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003120}
3121
3122/* Get the monitoring functions started */
3123static inline void nct6775_init_device(struct nct6775_data *data)
3124{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003125 int i;
3126 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003127
3128 /* Start monitoring if needed */
3129 if (data->REG_CONFIG) {
3130 tmp = nct6775_read_value(data, data->REG_CONFIG);
3131 if (!(tmp & 0x01))
3132 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3133 }
3134
Guenter Roeckaa136e52012-12-04 03:26:05 -08003135 /* Enable temperature sensors if needed */
3136 for (i = 0; i < NUM_TEMP; i++) {
3137 if (!(data->have_temp & (1 << i)))
3138 continue;
3139 if (!data->reg_temp_config[i])
3140 continue;
3141 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3142 if (tmp & 0x01)
3143 nct6775_write_value(data, data->reg_temp_config[i],
3144 tmp & 0xfe);
3145 }
3146
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003147 /* Enable VBAT monitoring if needed */
3148 tmp = nct6775_read_value(data, data->REG_VBAT);
3149 if (!(tmp & 0x01))
3150 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003151
3152 diode = nct6775_read_value(data, data->REG_DIODE);
3153
3154 for (i = 0; i < data->temp_fixed_num; i++) {
3155 if (!(data->have_temp_fixed & (1 << i)))
3156 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003157 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3158 data->temp_type[i]
3159 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003160 else /* thermistor */
3161 data->temp_type[i] = 4;
3162 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003163}
3164
Guenter Roeckf73cf632013-03-18 09:22:50 -07003165static void
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003166nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
3167 struct nct6775_data *data)
3168{
3169 int regval;
David Bartley578ab5f2013-06-24 22:28:28 -07003170 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3171 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003172
3173 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3174 if (data->kind == nct6775) {
3175 regval = superio_inb(sio_data->sioreg, 0x2c);
3176
3177 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003178 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003179
3180 /* On NCT6775, fan4 shares pins with the fdc interface */
3181 fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003182 fan4min = false;
3183 fan5pin = false;
3184 fan6pin = false;
3185 pwm4pin = false;
3186 pwm5pin = false;
3187 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003188 } else if (data->kind == nct6776) {
3189 bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
3190
3191 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3192 regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
3193
3194 if (regval & 0x80)
3195 fan3pin = gpok;
3196 else
3197 fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
3198
3199 if (regval & 0x40)
3200 fan4pin = gpok;
3201 else
3202 fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
3203
3204 if (regval & 0x20)
3205 fan5pin = gpok;
3206 else
3207 fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
3208
3209 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003210 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003211 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003212 pwm4pin = false;
3213 pwm5pin = false;
3214 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003215 } else if (data->kind == nct6106) {
3216 regval = superio_inb(sio_data->sioreg, 0x24);
3217 fan3pin = !(regval & 0x80);
3218 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003219
3220 fan4pin = false;
3221 fan4min = false;
3222 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003223 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003224 pwm4pin = false;
3225 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003226 pwm6pin = false;
3227 } else { /* NCT6779D or NCT6791D */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003228 regval = superio_inb(sio_data->sioreg, 0x1c);
3229
3230 fan3pin = !(regval & (1 << 5));
3231 fan4pin = !(regval & (1 << 6));
3232 fan5pin = !(regval & (1 << 7));
3233
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003234 pwm3pin = !(regval & (1 << 0));
3235 pwm4pin = !(regval & (1 << 1));
3236 pwm5pin = !(regval & (1 << 2));
3237
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003238 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003239
3240 if (data->kind == nct6791) {
3241 regval = superio_inb(sio_data->sioreg, 0x2d);
3242 fan6pin = (regval & (1 << 1));
3243 pwm6pin = (regval & (1 << 0));
3244 } else { /* NCT6779D */
3245 fan6pin = false;
3246 pwm6pin = false;
3247 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003248 }
3249
David Bartley578ab5f2013-06-24 22:28:28 -07003250 /* fan 1 and 2 (0x03) are always present */
3251 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3252 (fan5pin << 4) | (fan6pin << 5);
3253 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3254 (fan5pin << 4);
3255 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3256 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003257}
3258
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003259static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3260 int *available, int *mask)
3261{
3262 int i;
3263 u8 src;
3264
3265 for (i = 0; i < data->pwm_num && *available; i++) {
3266 int index;
3267
3268 if (!regp[i])
3269 continue;
3270 src = nct6775_read_value(data, regp[i]);
3271 src &= 0x1f;
3272 if (!src || (*mask & (1 << src)))
3273 continue;
3274 if (src >= data->temp_label_num ||
3275 !strlen(data->temp_label[src]))
3276 continue;
3277
3278 index = __ffs(*available);
3279 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3280 *available &= ~(1 << index);
3281 *mask |= 1 << src;
3282 }
3283}
3284
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003285static int nct6775_probe(struct platform_device *pdev)
3286{
3287 struct device *dev = &pdev->dev;
3288 struct nct6775_sio_data *sio_data = dev->platform_data;
3289 struct nct6775_data *data;
3290 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003291 int i, s, err = 0;
3292 int src, mask, available;
3293 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
3294 const u16 *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003295 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003296 int num_reg_temp;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003297 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003298 struct attribute_group *group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003299
3300 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3301 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3302 DRVNAME))
3303 return -EBUSY;
3304
3305 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3306 GFP_KERNEL);
3307 if (!data)
3308 return -ENOMEM;
3309
3310 data->kind = sio_data->kind;
3311 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003312 mutex_init(&data->update_lock);
3313 data->name = nct6775_device_names[data->kind];
3314 data->bank = 0xff; /* Force initial bank selection */
3315 platform_set_drvdata(pdev, data);
3316
3317 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003318 case nct6106:
3319 data->in_num = 9;
3320 data->pwm_num = 3;
3321 data->auto_pwm_num = 4;
3322 data->temp_fixed_num = 3;
3323 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003324 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003325
3326 data->fan_from_reg = fan_from_reg13;
3327 data->fan_from_reg_min = fan_from_reg13;
3328
3329 data->temp_label = nct6776_temp_label;
3330 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3331
3332 data->REG_VBAT = NCT6106_REG_VBAT;
3333 data->REG_DIODE = NCT6106_REG_DIODE;
3334 data->DIODE_MASK = NCT6106_DIODE_MASK;
3335 data->REG_VIN = NCT6106_REG_IN;
3336 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3337 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3338 data->REG_TARGET = NCT6106_REG_TARGET;
3339 data->REG_FAN = NCT6106_REG_FAN;
3340 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3341 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3342 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3343 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3344 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3345 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3346 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3347 data->REG_PWM[0] = NCT6106_REG_PWM;
3348 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3349 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3350 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3351 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3352 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3353 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3354 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3355 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3356 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3357 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3358 data->REG_CRITICAL_TEMP_TOLERANCE
3359 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3360 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3361 data->CRITICAL_PWM_ENABLE_MASK
3362 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3363 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3364 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3365 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3366 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3367 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3368 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3369 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3370 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3371 data->REG_ALARM = NCT6106_REG_ALARM;
3372 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003373 data->REG_BEEP = NCT6106_REG_BEEP;
3374 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003375
3376 reg_temp = NCT6106_REG_TEMP;
3377 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
3378 reg_temp_over = NCT6106_REG_TEMP_OVER;
3379 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3380 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3381 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3382 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003383 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3384 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003385
3386 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003387 case nct6775:
3388 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003389 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003390 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003391 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003392 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003393 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003394 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003395
3396 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003397 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003398
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003399 data->fan_from_reg = fan_from_reg16;
3400 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003401 data->target_temp_mask = 0x7f;
3402 data->tolerance_mask = 0x0f;
3403 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003404
Guenter Roeckaa136e52012-12-04 03:26:05 -08003405 data->temp_label = nct6775_temp_label;
3406 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3407
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003408 data->REG_CONFIG = NCT6775_REG_CONFIG;
3409 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003410 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003411 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003412 data->REG_VIN = NCT6775_REG_IN;
3413 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3414 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003415 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003416 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003417 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003418 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003419 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003420 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003421 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3422 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3423 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003424 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003425 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3426 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3427 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3428 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003429 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003430 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3431 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3432 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003433 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3434 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3435 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3436 data->REG_CRITICAL_TEMP_TOLERANCE
3437 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003438 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3439 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003440 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003441 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3442 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3443 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3444 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003445 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003446 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003447
3448 reg_temp = NCT6775_REG_TEMP;
3449 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
3450 reg_temp_over = NCT6775_REG_TEMP_OVER;
3451 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3452 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3453 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3454 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3455
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003456 break;
3457 case nct6776:
3458 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003459 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003460 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003461 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003462 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003463 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003464 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003465
3466 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003467 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003468
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003469 data->fan_from_reg = fan_from_reg13;
3470 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003471 data->target_temp_mask = 0xff;
3472 data->tolerance_mask = 0x07;
3473 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003474
Guenter Roeckaa136e52012-12-04 03:26:05 -08003475 data->temp_label = nct6776_temp_label;
3476 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3477
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003478 data->REG_CONFIG = NCT6775_REG_CONFIG;
3479 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003480 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003481 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003482 data->REG_VIN = NCT6775_REG_IN;
3483 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3484 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003485 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003486 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003487 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003488 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003489 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003490 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003491 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3492 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3493 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3494 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003495 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003496 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3497 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003498 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3499 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003500 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3501 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3502 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003503 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3504 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3505 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3506 data->REG_CRITICAL_TEMP_TOLERANCE
3507 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003508 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3509 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003510 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003511 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3512 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3513 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3514 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003515 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003516 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003517
3518 reg_temp = NCT6775_REG_TEMP;
3519 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
3520 reg_temp_over = NCT6775_REG_TEMP_OVER;
3521 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3522 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3523 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3524 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3525
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003526 break;
3527 case nct6779:
3528 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003529 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003530 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003532 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003533 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003534 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003535
3536 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003537 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003538
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003539 data->fan_from_reg = fan_from_reg13;
3540 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003541 data->target_temp_mask = 0xff;
3542 data->tolerance_mask = 0x07;
3543 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003544
Guenter Roeckaa136e52012-12-04 03:26:05 -08003545 data->temp_label = nct6779_temp_label;
3546 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3547
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003548 data->REG_CONFIG = NCT6775_REG_CONFIG;
3549 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003550 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003551 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552 data->REG_VIN = NCT6779_REG_IN;
3553 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3554 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003555 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003556 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003557 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003558 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003559 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003560 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003561 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3562 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3563 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3564 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003565 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003566 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3567 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003568 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3569 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003570 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3571 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3572 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003573 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3574 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3575 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3576 data->REG_CRITICAL_TEMP_TOLERANCE
3577 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003578 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3579 data->CRITICAL_PWM_ENABLE_MASK
3580 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3581 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003582 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3583 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003584 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003585 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3586 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3587 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3588 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003589 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003590 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003591
3592 reg_temp = NCT6779_REG_TEMP;
3593 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
3594 reg_temp_over = NCT6779_REG_TEMP_OVER;
3595 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3596 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3597 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3598 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3599
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003600 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003601 case nct6791:
3602 data->in_num = 15;
3603 data->pwm_num = 6;
3604 data->auto_pwm_num = 4;
3605 data->has_fan_div = false;
3606 data->temp_fixed_num = 6;
3607 data->num_temp_alarms = 2;
3608 data->num_temp_beeps = 2;
3609
3610 data->ALARM_BITS = NCT6791_ALARM_BITS;
3611 data->BEEP_BITS = NCT6779_BEEP_BITS;
3612
3613 data->fan_from_reg = fan_from_reg13;
3614 data->fan_from_reg_min = fan_from_reg13;
3615 data->target_temp_mask = 0xff;
3616 data->tolerance_mask = 0x07;
3617 data->speed_tolerance_limit = 63;
3618
3619 data->temp_label = nct6779_temp_label;
3620 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3621
3622 data->REG_CONFIG = NCT6775_REG_CONFIG;
3623 data->REG_VBAT = NCT6775_REG_VBAT;
3624 data->REG_DIODE = NCT6775_REG_DIODE;
3625 data->DIODE_MASK = NCT6775_DIODE_MASK;
3626 data->REG_VIN = NCT6779_REG_IN;
3627 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3628 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3629 data->REG_TARGET = NCT6775_REG_TARGET;
3630 data->REG_FAN = NCT6779_REG_FAN;
3631 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3632 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3633 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3634 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3635 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3636 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3637 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3638 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3639 data->REG_PWM[0] = NCT6775_REG_PWM;
3640 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3641 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3642 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3643 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
3644 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3645 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3646 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3647 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3648 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3649 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3650 data->REG_CRITICAL_TEMP_TOLERANCE
3651 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3652 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3653 data->CRITICAL_PWM_ENABLE_MASK
3654 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3655 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3656 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3657 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3658 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
3659 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3660 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3661 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3662 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
3663 data->REG_ALARM = NCT6791_REG_ALARM;
3664 data->REG_BEEP = NCT6776_REG_BEEP;
3665
3666 reg_temp = NCT6779_REG_TEMP;
3667 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
3668 reg_temp_over = NCT6779_REG_TEMP_OVER;
3669 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3670 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3671 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3672 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3673
3674 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003675 default:
3676 return -ENODEV;
3677 }
3678 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003679 data->have_temp = 0;
3680
3681 /*
3682 * On some boards, not all available temperature sources are monitored,
3683 * even though some of the monitoring registers are unused.
3684 * Get list of unused monitoring registers, then detect if any fan
3685 * controls are configured to use unmonitored temperature sources.
3686 * If so, assign the unmonitored temperature sources to available
3687 * monitoring registers.
3688 */
3689 mask = 0;
3690 available = 0;
3691 for (i = 0; i < num_reg_temp; i++) {
3692 if (reg_temp[i] == 0)
3693 continue;
3694
3695 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3696 if (!src || (mask & (1 << src)))
3697 available |= 1 << i;
3698
3699 mask |= 1 << src;
3700 }
3701
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003702 /*
3703 * Now find unmonitored temperature registers and enable monitoring
3704 * if additional monitoring registers are available.
3705 */
3706 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3707 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3708
Guenter Roeckaa136e52012-12-04 03:26:05 -08003709 mask = 0;
3710 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3711 for (i = 0; i < num_reg_temp; i++) {
3712 if (reg_temp[i] == 0)
3713 continue;
3714
3715 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3716 if (!src || (mask & (1 << src)))
3717 continue;
3718
3719 if (src >= data->temp_label_num ||
3720 !strlen(data->temp_label[src])) {
3721 dev_info(dev,
3722 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3723 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3724 continue;
3725 }
3726
3727 mask |= 1 << src;
3728
3729 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3730 if (src <= data->temp_fixed_num) {
3731 data->have_temp |= 1 << (src - 1);
3732 data->have_temp_fixed |= 1 << (src - 1);
3733 data->reg_temp[0][src - 1] = reg_temp[i];
3734 data->reg_temp[1][src - 1] = reg_temp_over[i];
3735 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003736 if (reg_temp_crit_h && reg_temp_crit_h[i])
3737 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3738 else if (reg_temp_crit[src - 1])
3739 data->reg_temp[3][src - 1]
3740 = reg_temp_crit[src - 1];
3741 if (reg_temp_crit_l && reg_temp_crit_l[i])
3742 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003743 data->reg_temp_config[src - 1] = reg_temp_config[i];
3744 data->temp_src[src - 1] = src;
3745 continue;
3746 }
3747
3748 if (s >= NUM_TEMP)
3749 continue;
3750
3751 /* Use dynamic index for other sources */
3752 data->have_temp |= 1 << s;
3753 data->reg_temp[0][s] = reg_temp[i];
3754 data->reg_temp[1][s] = reg_temp_over[i];
3755 data->reg_temp[2][s] = reg_temp_hyst[i];
3756 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003757 if (reg_temp_crit_h && reg_temp_crit_h[i])
3758 data->reg_temp[3][s] = reg_temp_crit_h[i];
3759 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003760 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003761 if (reg_temp_crit_l && reg_temp_crit_l[i])
3762 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003763
3764 data->temp_src[s] = src;
3765 s++;
3766 }
3767
3768#ifdef USE_ALTERNATE
3769 /*
3770 * Go through the list of alternate temp registers and enable
3771 * if possible.
3772 * The temperature is already monitored if the respective bit in <mask>
3773 * is set.
3774 */
3775 for (i = 0; i < data->temp_label_num - 1; i++) {
3776 if (!reg_temp_alternate[i])
3777 continue;
3778 if (mask & (1 << (i + 1)))
3779 continue;
3780 if (i < data->temp_fixed_num) {
3781 if (data->have_temp & (1 << i))
3782 continue;
3783 data->have_temp |= 1 << i;
3784 data->have_temp_fixed |= 1 << i;
3785 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003786 if (i < num_reg_temp) {
3787 data->reg_temp[1][i] = reg_temp_over[i];
3788 data->reg_temp[2][i] = reg_temp_hyst[i];
3789 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003790 data->temp_src[i] = i + 1;
3791 continue;
3792 }
3793
3794 if (s >= NUM_TEMP) /* Abort if no more space */
3795 break;
3796
3797 data->have_temp |= 1 << s;
3798 data->reg_temp[0][s] = reg_temp_alternate[i];
3799 data->temp_src[s] = i + 1;
3800 s++;
3801 }
3802#endif /* USE_ALTERNATE */
3803
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003804 /* Initialize the chip */
3805 nct6775_init_device(data);
3806
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003807 err = superio_enter(sio_data->sioreg);
3808 if (err)
3809 return err;
3810
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003811 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3812 switch (data->kind) {
3813 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003814 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003815 break;
3816 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003817 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003818 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003819 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003820 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003821 case nct6791:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003822 break;
3823 }
3824
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003825 /*
3826 * Read VID value
3827 * We can get the VID input values directly at logical device D 0xe3.
3828 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003829 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003830 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3831 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3832 data->vrm = vid_which_vrm();
3833 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003834
3835 if (fan_debounce) {
3836 u8 tmp;
3837
3838 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3839 tmp = superio_inb(sio_data->sioreg,
3840 NCT6775_REG_CR_FAN_DEBOUNCE);
3841 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003842 case nct6106:
3843 tmp |= 0xe0;
3844 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003845 case nct6775:
3846 tmp |= 0x1e;
3847 break;
3848 case nct6776:
3849 case nct6779:
3850 tmp |= 0x3e;
3851 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003852 case nct6791:
3853 tmp |= 0x7e;
3854 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003855 }
3856 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3857 tmp);
3858 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3859 data->name);
3860 }
3861
Guenter Roeckf73cf632013-03-18 09:22:50 -07003862 nct6775_check_fan_inputs(sio_data, data);
3863
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003864 superio_exit(sio_data->sioreg);
3865
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003866 /* Read fan clock dividers immediately */
3867 nct6775_init_fan_common(dev, data);
3868
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003869 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003870 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3871 data->pwm_num);
3872 if (IS_ERR(group)) {
3873 err = PTR_ERR(group);
3874 goto exit_remove;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003875 }
Guenter Roeckf73cf632013-03-18 09:22:50 -07003876 data->group_pwm = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003877
Guenter Roeckf73cf632013-03-18 09:22:50 -07003878 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3879 fls(data->have_in));
3880 if (IS_ERR(group)) {
3881 err = PTR_ERR(group);
3882 goto exit_remove;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003883 }
Guenter Roeckf73cf632013-03-18 09:22:50 -07003884 data->group_in = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003885
Guenter Roeckf73cf632013-03-18 09:22:50 -07003886 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3887 fls(data->has_fan));
3888 if (IS_ERR(group)) {
3889 err = PTR_ERR(group);
3890 goto exit_remove;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003891 }
Guenter Roeckf73cf632013-03-18 09:22:50 -07003892 data->group_fan = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003893
Guenter Roeckf73cf632013-03-18 09:22:50 -07003894 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3895 fls(data->have_temp));
3896 if (IS_ERR(group)) {
3897 err = PTR_ERR(group);
3898 goto exit_remove;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003899 }
Guenter Roeckf73cf632013-03-18 09:22:50 -07003900 data->group_temp = group;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003901
Guenter Roeckf73cf632013-03-18 09:22:50 -07003902 err = sysfs_create_group(&dev->kobj, &nct6775_group_other);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003903 if (err)
3904 goto exit_remove;
3905
3906 data->hwmon_dev = hwmon_device_register(dev);
3907 if (IS_ERR(data->hwmon_dev)) {
3908 err = PTR_ERR(data->hwmon_dev);
3909 goto exit_remove;
3910 }
3911
3912 return 0;
3913
3914exit_remove:
3915 nct6775_device_remove_files(dev);
3916 return err;
3917}
3918
3919static int nct6775_remove(struct platform_device *pdev)
3920{
3921 struct nct6775_data *data = platform_get_drvdata(pdev);
3922
3923 hwmon_device_unregister(data->hwmon_dev);
3924 nct6775_device_remove_files(&pdev->dev);
3925
3926 return 0;
3927}
3928
Guenter Roeck84d19d92012-12-04 08:01:39 -08003929#ifdef CONFIG_PM
3930static int nct6775_suspend(struct device *dev)
3931{
3932 struct nct6775_data *data = nct6775_update_device(dev);
3933 struct nct6775_sio_data *sio_data = dev->platform_data;
3934
3935 mutex_lock(&data->update_lock);
3936 data->vbat = nct6775_read_value(data, data->REG_VBAT);
3937 if (sio_data->kind == nct6775) {
3938 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
3939 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
3940 }
3941 mutex_unlock(&data->update_lock);
3942
3943 return 0;
3944}
3945
3946static int nct6775_resume(struct device *dev)
3947{
3948 struct nct6775_data *data = dev_get_drvdata(dev);
3949 struct nct6775_sio_data *sio_data = dev->platform_data;
3950 int i, j;
3951
3952 mutex_lock(&data->update_lock);
3953 data->bank = 0xff; /* Force initial bank selection */
3954
3955 /* Restore limits */
3956 for (i = 0; i < data->in_num; i++) {
3957 if (!(data->have_in & (1 << i)))
3958 continue;
3959
3960 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
3961 data->in[i][1]);
3962 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
3963 data->in[i][2]);
3964 }
3965
Guenter Roeckc409fd42013-04-09 05:04:00 -07003966 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08003967 if (!(data->has_fan_min & (1 << i)))
3968 continue;
3969
3970 nct6775_write_value(data, data->REG_FAN_MIN[i],
3971 data->fan_min[i]);
3972 }
3973
3974 for (i = 0; i < NUM_TEMP; i++) {
3975 if (!(data->have_temp & (1 << i)))
3976 continue;
3977
Guenter Roeckc409fd42013-04-09 05:04:00 -07003978 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08003979 if (data->reg_temp[j][i])
3980 nct6775_write_temp(data, data->reg_temp[j][i],
3981 data->temp[j][i]);
3982 }
3983
3984 /* Restore other settings */
3985 nct6775_write_value(data, data->REG_VBAT, data->vbat);
3986 if (sio_data->kind == nct6775) {
3987 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
3988 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
3989 }
3990
3991 /* Force re-reading all values */
3992 data->valid = false;
3993 mutex_unlock(&data->update_lock);
3994
3995 return 0;
3996}
3997
3998static const struct dev_pm_ops nct6775_dev_pm_ops = {
3999 .suspend = nct6775_suspend,
4000 .resume = nct6775_resume,
4001};
4002
4003#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops)
4004#else
4005#define NCT6775_DEV_PM_OPS NULL
4006#endif /* CONFIG_PM */
4007
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004008static struct platform_driver nct6775_driver = {
4009 .driver = {
4010 .owner = THIS_MODULE,
4011 .name = DRVNAME,
Guenter Roeck84d19d92012-12-04 08:01:39 -08004012 .pm = NCT6775_DEV_PM_OPS,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004013 },
4014 .probe = nct6775_probe,
4015 .remove = nct6775_remove,
4016};
4017
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004018static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004019 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004020 "NCT6775F",
4021 "NCT6776D/F",
4022 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004023 "NCT6791D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004024};
4025
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004026/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004027static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004028{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004029 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004030 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004031 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004032
4033 err = superio_enter(sioaddr);
4034 if (err)
4035 return err;
4036
4037 if (force_id)
4038 val = force_id;
4039 else
4040 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4041 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4042 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004043 case SIO_NCT6106_ID:
4044 sio_data->kind = nct6106;
4045 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004046 case SIO_NCT6775_ID:
4047 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004048 break;
4049 case SIO_NCT6776_ID:
4050 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004051 break;
4052 case SIO_NCT6779_ID:
4053 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004054 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004055 case SIO_NCT6791_ID:
4056 sio_data->kind = nct6791;
4057 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004058 default:
4059 if (val != 0xffff)
4060 pr_debug("unsupported chip ID: 0x%04x\n", val);
4061 superio_exit(sioaddr);
4062 return -ENODEV;
4063 }
4064
4065 /* We have a known chip, find the HWM I/O address */
4066 superio_select(sioaddr, NCT6775_LD_HWM);
4067 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4068 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004069 addr = val & IOREGION_ALIGNMENT;
4070 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004071 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4072 superio_exit(sioaddr);
4073 return -ENODEV;
4074 }
4075
4076 /* Activate logical device if needed */
4077 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4078 if (!(val & 0x01)) {
4079 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4080 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4081 }
David Bartley578ab5f2013-06-24 22:28:28 -07004082 if (sio_data->kind == nct6791) {
4083 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4084 if (val & 0x10) {
4085 pr_info("Enabling hardware monitor logical device mappings.\n");
4086 superio_outb(sioaddr,
4087 NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4088 val & ~0x10);
4089 }
4090 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004091
4092 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004093 pr_info("Found %s or compatible chip at %#x:%#x\n",
4094 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004095 sio_data->sioreg = sioaddr;
4096
Guenter Roeck698a7c22013-04-05 07:35:25 -07004097 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004098}
4099
4100/*
4101 * when Super-I/O functions move to a separate file, the Super-I/O
4102 * bus will manage the lifetime of the device and this module will only keep
4103 * track of the nct6775 driver. But since we platform_device_alloc(), we
4104 * must keep track of the device
4105 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004106static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004107
4108static int __init sensors_nct6775_init(void)
4109{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004110 int i, err;
4111 bool found = false;
4112 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004113 struct resource res;
4114 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004115 int sioaddr[2] = { 0x2e, 0x4e };
4116
4117 err = platform_driver_register(&nct6775_driver);
4118 if (err)
4119 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004120
4121 /*
4122 * initialize sio_data->kind and sio_data->sioreg.
4123 *
4124 * when Super-I/O functions move to a separate file, the Super-I/O
4125 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4126 * nct6775 hardware monitor, and call probe()
4127 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004128 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4129 address = nct6775_find(sioaddr[i], &sio_data);
4130 if (address <= 0)
4131 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004132
Guenter Roeck698a7c22013-04-05 07:35:25 -07004133 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004134
Guenter Roeck698a7c22013-04-05 07:35:25 -07004135 pdev[i] = platform_device_alloc(DRVNAME, address);
4136 if (!pdev[i]) {
4137 err = -ENOMEM;
4138 goto exit_device_put;
4139 }
4140
4141 err = platform_device_add_data(pdev[i], &sio_data,
4142 sizeof(struct nct6775_sio_data));
4143 if (err)
4144 goto exit_device_put;
4145
4146 memset(&res, 0, sizeof(res));
4147 res.name = DRVNAME;
4148 res.start = address + IOREGION_OFFSET;
4149 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4150 res.flags = IORESOURCE_IO;
4151
4152 err = acpi_check_resource_conflict(&res);
4153 if (err) {
4154 platform_device_put(pdev[i]);
4155 pdev[i] = NULL;
4156 continue;
4157 }
4158
4159 err = platform_device_add_resources(pdev[i], &res, 1);
4160 if (err)
4161 goto exit_device_put;
4162
4163 /* platform_device_add calls probe() */
4164 err = platform_device_add(pdev[i]);
4165 if (err)
4166 goto exit_device_put;
4167 }
4168 if (!found) {
4169 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004170 goto exit_unregister;
4171 }
4172
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004173 return 0;
4174
4175exit_device_put:
Guenter Roeck698a7c22013-04-05 07:35:25 -07004176 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4177 if (pdev[i])
4178 platform_device_put(pdev[i]);
4179 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004180exit_unregister:
4181 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004182 return err;
4183}
4184
4185static void __exit sensors_nct6775_exit(void)
4186{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004187 int i;
4188
4189 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4190 if (pdev[i])
4191 platform_device_unregister(pdev[i]);
4192 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004193 platform_driver_unregister(&nct6775_driver);
4194}
4195
4196MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
4197MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
4198MODULE_LICENSE("GPL");
4199
4200module_init(sensors_nct6775_init);
4201module_exit(sensors_nct6775_exit);