blob: 59d9a3fc96b70cd828c29b66ced2021ceeaa9ca4 [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
Jean Delvare7c81c60f2014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * 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
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800277static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
278
Guenter Roeckaa136e52012-12-04 03:26:05 -0800279static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
280 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
281static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
282 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
283static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
284 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
285
286static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
287 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
288
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800289static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700290 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800291
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800292static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700293 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800294static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700295 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800296static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700297 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800298static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700299 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800300static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700301 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800302
Guenter Roeckaa136e52012-12-04 03:26:05 -0800303static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
304
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800305static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700306 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800307static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700308 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800309
310#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
311#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
312
313static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
314
315static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800317static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700318 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800319
Guenter Roeckaa136e52012-12-04 03:26:05 -0800320static const char *const nct6775_temp_label[] = {
321 "",
322 "SYSTIN",
323 "CPUTIN",
324 "AUXTIN",
325 "AMD SB-TSI",
326 "PECI Agent 0",
327 "PECI Agent 1",
328 "PECI Agent 2",
329 "PECI Agent 3",
330 "PECI Agent 4",
331 "PECI Agent 5",
332 "PECI Agent 6",
333 "PECI Agent 7",
334 "PCH_CHIP_CPU_MAX_TEMP",
335 "PCH_CHIP_TEMP",
336 "PCH_CPU_TEMP",
337 "PCH_MCH_TEMP",
338 "PCH_DIM0_TEMP",
339 "PCH_DIM1_TEMP",
340 "PCH_DIM2_TEMP",
341 "PCH_DIM3_TEMP"
342};
343
344static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
345 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
346
347static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
348 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
349 0xa07 };
350
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700351/* NCT6776 specific data */
352
353static const s8 NCT6776_ALARM_BITS[] = {
354 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
355 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
356 -1, /* unused */
357 6, 7, 11, 10, 23, /* fan1..fan5 */
358 -1, -1, -1, /* unused */
359 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
360 12, 9 }; /* intrusion0, intrusion1 */
361
Guenter Roeck30846992013-06-24 22:21:59 -0700362static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
363
364static const s8 NCT6776_BEEP_BITS[] = {
365 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
366 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
367 24, /* global beep enable */
368 25, 26, 27, 28, 29, /* fan1..fan5 */
369 -1, -1, -1, /* unused */
370 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
371 30, 31 }; /* intrusion0, intrusion1 */
372
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800373static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700374 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800375
David Bartley578ab5f2013-06-24 22:28:28 -0700376static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
377static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800378
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800379static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800380static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800381
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800382static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700383 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800384
Guenter Roeckaa136e52012-12-04 03:26:05 -0800385static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
386 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
387
388static const char *const nct6776_temp_label[] = {
389 "",
390 "SYSTIN",
391 "CPUTIN",
392 "AUXTIN",
393 "SMBUSMASTER 0",
394 "SMBUSMASTER 1",
395 "SMBUSMASTER 2",
396 "SMBUSMASTER 3",
397 "SMBUSMASTER 4",
398 "SMBUSMASTER 5",
399 "SMBUSMASTER 6",
400 "SMBUSMASTER 7",
401 "PECI Agent 0",
402 "PECI Agent 1",
403 "PCH_CHIP_CPU_MAX_TEMP",
404 "PCH_CHIP_TEMP",
405 "PCH_CPU_TEMP",
406 "PCH_MCH_TEMP",
407 "PCH_DIM0_TEMP",
408 "PCH_DIM1_TEMP",
409 "PCH_DIM2_TEMP",
410 "PCH_DIM3_TEMP",
411 "BYTE_TEMP"
412};
413
414static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
415 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
416
417static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
418 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700420/* NCT6779 specific data */
421
422static const u16 NCT6779_REG_IN[] = {
423 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
424 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
425
426static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
427 0x459, 0x45A, 0x45B, 0x568 };
428
429static const s8 NCT6779_ALARM_BITS[] = {
430 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
431 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
432 -1, /* unused */
433 6, 7, 11, 10, 23, /* fan1..fan5 */
434 -1, -1, -1, /* unused */
435 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
436 12, 9 }; /* intrusion0, intrusion1 */
437
Guenter Roeck30846992013-06-24 22:21:59 -0700438static const s8 NCT6779_BEEP_BITS[] = {
439 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
440 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
441 24, /* global beep enable */
442 25, 26, 27, 28, 29, /* fan1..fan5 */
443 -1, -1, -1, /* unused */
444 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
445 30, 31 }; /* intrusion0, intrusion1 */
446
David Bartley578ab5f2013-06-24 22:28:28 -0700447static const u16 NCT6779_REG_FAN[] = {
448 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800449static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700450 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800451
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800452static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700453 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700454#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800455static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700456 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800457
Guenter Roeckaa136e52012-12-04 03:26:05 -0800458static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800459static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800460static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
461 0x18, 0x152 };
462static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
463 0x3a, 0x153 };
464static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
465 0x39, 0x155 };
466
467static const u16 NCT6779_REG_TEMP_OFFSET[] = {
468 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
469
470static const char *const nct6779_temp_label[] = {
471 "",
472 "SYSTIN",
473 "CPUTIN",
474 "AUXTIN0",
475 "AUXTIN1",
476 "AUXTIN2",
477 "AUXTIN3",
478 "",
479 "SMBUSMASTER 0",
480 "SMBUSMASTER 1",
481 "SMBUSMASTER 2",
482 "SMBUSMASTER 3",
483 "SMBUSMASTER 4",
484 "SMBUSMASTER 5",
485 "SMBUSMASTER 6",
486 "SMBUSMASTER 7",
487 "PECI Agent 0",
488 "PECI Agent 1",
489 "PCH_CHIP_CPU_MAX_TEMP",
490 "PCH_CHIP_TEMP",
491 "PCH_CPU_TEMP",
492 "PCH_MCH_TEMP",
493 "PCH_DIM0_TEMP",
494 "PCH_DIM1_TEMP",
495 "PCH_DIM2_TEMP",
496 "PCH_DIM3_TEMP",
497 "BYTE_TEMP"
498};
499
500static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
501 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
502 0, 0, 0, 0, 0, 0, 0, 0,
503 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
504 0x408, 0 };
505
506static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
507 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
508
David Bartley578ab5f2013-06-24 22:28:28 -0700509/* NCT6791 specific data */
510
511#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
512
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800513static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
514static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
515static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
516static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
517static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
518static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
519
David Bartley578ab5f2013-06-24 22:28:28 -0700520static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
521 0x459, 0x45A, 0x45B, 0x568, 0x45D };
522
523static const s8 NCT6791_ALARM_BITS[] = {
524 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
525 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
526 -1, /* unused */
527 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
528 -1, -1, /* unused */
529 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
530 12, 9 }; /* intrusion0, intrusion1 */
531
532
Guenter Roeck6c009502012-07-01 08:23:15 -0700533/* NCT6102D/NCT6106D specific data */
534
535#define NCT6106_REG_VBAT 0x318
536#define NCT6106_REG_DIODE 0x319
537#define NCT6106_DIODE_MASK 0x01
538
539static const u16 NCT6106_REG_IN_MAX[] = {
540 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
541static const u16 NCT6106_REG_IN_MIN[] = {
542 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
543static const u16 NCT6106_REG_IN[] = {
544 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
545
546static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800547static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700548static const u16 NCT6106_REG_TEMP_HYST[] = {
549 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
550static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700551 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
552static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
553 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
554static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
555 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700556static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
557static const u16 NCT6106_REG_TEMP_CONFIG[] = {
558 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
559
560static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
561static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
562static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
563static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
564
565static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
566static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
567static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
568static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
569static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
570static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
571static const u16 NCT6106_REG_TEMP_SOURCE[] = {
572 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
573
574static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
575static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
576 0x11b, 0x12b, 0x13b };
577
578static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
579#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
580static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
581
582static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
583static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
584static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
585static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
586static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
587static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
588
589static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
590
591static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
592static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
593static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
594static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
595static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
596static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
597
598static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
599static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
600
601static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
602 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
603
604static const s8 NCT6106_ALARM_BITS[] = {
605 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
606 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
607 -1, /* unused */
608 32, 33, 34, -1, -1, /* fan1..fan5 */
609 -1, -1, -1, /* unused */
610 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
611 48, -1 /* intrusion0, intrusion1 */
612};
613
Guenter Roeck30846992013-06-24 22:21:59 -0700614static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
615 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
616
617static const s8 NCT6106_BEEP_BITS[] = {
618 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
619 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
620 32, /* global beep enable */
621 24, 25, 26, 27, 28, /* fan1..fan5 */
622 -1, -1, -1, /* unused */
623 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
624 34, -1 /* intrusion0, intrusion1 */
625};
626
Guenter Roeck6c009502012-07-01 08:23:15 -0700627static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
628 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
629
630static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
631 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
632
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800633static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
634{
635 if (mode == 0 && pwm == 255)
636 return off;
637 return mode + 1;
638}
639
640static int pwm_enable_to_reg(enum pwm_enable mode)
641{
642 if (mode == off)
643 return 0;
644 return mode - 1;
645}
646
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700647/*
648 * Conversions
649 */
650
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800651/* 1 is DC mode, output in ms */
652static unsigned int step_time_from_reg(u8 reg, u8 mode)
653{
654 return mode ? 400 * reg : 100 * reg;
655}
656
657static u8 step_time_to_reg(unsigned int msec, u8 mode)
658{
659 return clamp_val((mode ? (msec + 200) / 400 :
660 (msec + 50) / 100), 1, 255);
661}
662
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800663static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
664{
665 if (reg == 0 || reg == 255)
666 return 0;
667 return 1350000U / (reg << divreg);
668}
669
670static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
671{
672 if ((reg & 0xff1f) == 0xff1f)
673 return 0;
674
675 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
676
677 if (reg == 0)
678 return 0;
679
680 return 1350000U / reg;
681}
682
683static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
684{
685 if (reg == 0 || reg == 0xffff)
686 return 0;
687
688 /*
689 * Even though the registers are 16 bit wide, the fan divisor
690 * still applies.
691 */
692 return 1350000U / (reg << divreg);
693}
694
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800695static u16 fan_to_reg(u32 fan, unsigned int divreg)
696{
697 if (!fan)
698 return 0;
699
700 return (1350000U / fan) >> divreg;
701}
702
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800703static inline unsigned int
704div_from_reg(u8 reg)
705{
706 return 1 << reg;
707}
708
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700709/*
710 * Some of the voltage inputs have internal scaling, the tables below
711 * contain 8 (the ADC LSB in mV) * scaling factor * 100
712 */
713static const u16 scale_in[15] = {
714 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
715 800, 800
716};
717
718static inline long in_from_reg(u8 reg, u8 nr)
719{
720 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
721}
722
723static inline u8 in_to_reg(u32 val, u8 nr)
724{
725 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
726}
727
728/*
729 * Data structures and manipulation thereof
730 */
731
732struct nct6775_data {
733 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700734 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700735 enum kinds kind;
736 const char *name;
737
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700738 int num_attr_groups;
739 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700740
Guenter Roeckb7a61352013-04-02 22:14:06 -0700741 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
742 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800743 */
744 u8 temp_src[NUM_TEMP];
745 u16 reg_temp_config[NUM_TEMP];
746 const char * const *temp_label;
747 int temp_label_num;
748
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700749 u16 REG_CONFIG;
750 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800751 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700752 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700753
754 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700755 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700756
757 const u16 *REG_VIN;
758 const u16 *REG_IN_MINMAX[2];
759
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800760 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800761 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800762 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800763 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800764 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700765 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800766 const u16 *REG_FAN_TIME[3];
767
768 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800769
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800770 const u8 *REG_PWM_MODE;
771 const u8 *PWM_MODE_MASK;
772
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800773 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
774 * [3]=pwm_max, [4]=pwm_step,
775 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800776 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800777 const u16 *REG_PWM_READ;
778
Guenter Roeck6c009502012-07-01 08:23:15 -0700779 const u16 *REG_CRITICAL_PWM_ENABLE;
780 u8 CRITICAL_PWM_ENABLE_MASK;
781 const u16 *REG_CRITICAL_PWM;
782
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800783 const u16 *REG_AUTO_TEMP;
784 const u16 *REG_AUTO_PWM;
785
786 const u16 *REG_CRITICAL_TEMP;
787 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
788
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800789 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800790 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800791 const u16 *REG_WEIGHT_TEMP_SEL;
792 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
793
Guenter Roeckaa136e52012-12-04 03:26:05 -0800794 const u16 *REG_TEMP_OFFSET;
795
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700796 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700797 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700798
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800799 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
800 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
801
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700802 struct mutex update_lock;
803 bool valid; /* true if following fields are valid */
804 unsigned long last_updated; /* In jiffies */
805
806 /* Register values */
807 u8 bank; /* current register bank */
808 u8 in_num; /* number of in inputs we have */
809 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700810 unsigned int rpm[NUM_FAN];
811 u16 fan_min[NUM_FAN];
812 u8 fan_pulses[NUM_FAN];
813 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800814 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800815 u8 has_fan; /* some fan inputs can be disabled */
816 u8 has_fan_min; /* some fans don't have min register */
817 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700818
Guenter Roeck6c009502012-07-01 08:23:15 -0700819 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700820 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800821 u8 temp_fixed_num; /* 3 or 6 */
822 u8 temp_type[NUM_TEMP_FIXED];
823 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300824 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
825 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700826 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700827 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700828
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800829 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700830 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
831 * 0->PWM variable duty cycle
832 */
833 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800834 /* 0->off
835 * 1->manual
836 * 2->thermal cruise mode (also called SmartFan I)
837 * 3->fan speed cruise mode
838 * 4->SmartFan III
839 * 5->enhanced variable thermal cruise (SmartFan IV)
840 */
David Bartley578ab5f2013-06-24 22:28:28 -0700841 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
842 * [3]=pwm_max, [4]=pwm_step,
843 * [5]=weight_duty_step, [6]=weight_duty_base
844 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800845
David Bartley578ab5f2013-06-24 22:28:28 -0700846 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800847 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700848 u32 target_speed[NUM_FAN];
849 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800850 u8 speed_tolerance_limit;
851
David Bartley578ab5f2013-06-24 22:28:28 -0700852 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800853 u8 tolerance_mask;
854
David Bartley578ab5f2013-06-24 22:28:28 -0700855 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800856
857 /* Automatic fan speed control registers */
858 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700859 u8 auto_pwm[NUM_FAN][7];
860 u8 auto_temp[NUM_FAN][7];
861 u8 pwm_temp_sel[NUM_FAN];
862 u8 pwm_weight_temp_sel[NUM_FAN];
863 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
864 * 2->temp_base
865 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800866
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700867 u8 vid;
868 u8 vrm;
869
Guenter Roeckf73cf632013-03-18 09:22:50 -0700870 bool have_vid;
871
Guenter Roeckaa136e52012-12-04 03:26:05 -0800872 u16 have_temp;
873 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700874 u16 have_in;
Guenter Roeck84d19d92012-12-04 08:01:39 -0800875#ifdef CONFIG_PM
876 /* Remember extra register values over suspend/resume */
877 u8 vbat;
878 u8 fandiv1;
879 u8 fandiv2;
880#endif
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700881};
882
883struct nct6775_sio_data {
884 int sioreg;
885 enum kinds kind;
886};
887
Guenter Roeckf73cf632013-03-18 09:22:50 -0700888struct sensor_device_template {
889 struct device_attribute dev_attr;
890 union {
891 struct {
892 u8 nr;
893 u8 index;
894 } s;
895 int index;
896 } u;
897 bool s2; /* true if both index and nr are used */
898};
899
900struct sensor_device_attr_u {
901 union {
902 struct sensor_device_attribute a1;
903 struct sensor_device_attribute_2 a2;
904 } u;
905 char name[32];
906};
907
908#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
909 .attr = {.name = _template, .mode = _mode }, \
910 .show = _show, \
911 .store = _store, \
912}
913
914#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
915 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
916 .u.index = _index, \
917 .s2 = false }
918
919#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
920 _nr, _index) \
921 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
922 .u.s.index = _index, \
923 .u.s.nr = _nr, \
924 .s2 = true }
925
926#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
927static struct sensor_device_template sensor_dev_template_##_name \
928 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
929 _index)
930
931#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
932 _nr, _index) \
933static struct sensor_device_template sensor_dev_template_##_name \
934 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
935 _nr, _index)
936
937struct sensor_template_group {
938 struct sensor_device_template **templates;
939 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
940 int base;
941};
942
943static struct attribute_group *
944nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
945 int repeat)
946{
947 struct attribute_group *group;
948 struct sensor_device_attr_u *su;
949 struct sensor_device_attribute *a;
950 struct sensor_device_attribute_2 *a2;
951 struct attribute **attrs;
952 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300953 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700954
955 if (repeat <= 0)
956 return ERR_PTR(-EINVAL);
957
958 t = tg->templates;
959 for (count = 0; *t; t++, count++)
960 ;
961
962 if (count == 0)
963 return ERR_PTR(-EINVAL);
964
965 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
966 if (group == NULL)
967 return ERR_PTR(-ENOMEM);
968
969 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
970 GFP_KERNEL);
971 if (attrs == NULL)
972 return ERR_PTR(-ENOMEM);
973
974 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
975 GFP_KERNEL);
976 if (su == NULL)
977 return ERR_PTR(-ENOMEM);
978
979 group->attrs = attrs;
980 group->is_visible = tg->is_visible;
981
982 for (i = 0; i < repeat; i++) {
983 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300984 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -0700985 snprintf(su->name, sizeof(su->name),
986 (*t)->dev_attr.attr.name, tg->base + i);
987 if ((*t)->s2) {
988 a2 = &su->u.a2;
989 a2->dev_attr.attr.name = su->name;
990 a2->nr = (*t)->u.s.nr + i;
991 a2->index = (*t)->u.s.index;
992 a2->dev_attr.attr.mode =
993 (*t)->dev_attr.attr.mode;
994 a2->dev_attr.show = (*t)->dev_attr.show;
995 a2->dev_attr.store = (*t)->dev_attr.store;
996 *attrs = &a2->dev_attr.attr;
997 } else {
998 a = &su->u.a1;
999 a->dev_attr.attr.name = su->name;
1000 a->index = (*t)->u.index + i;
1001 a->dev_attr.attr.mode =
1002 (*t)->dev_attr.attr.mode;
1003 a->dev_attr.show = (*t)->dev_attr.show;
1004 a->dev_attr.store = (*t)->dev_attr.store;
1005 *attrs = &a->dev_attr.attr;
1006 }
1007 attrs++;
1008 su++;
1009 t++;
1010 }
1011 }
1012
Guenter Roeckf73cf632013-03-18 09:22:50 -07001013 return group;
1014}
1015
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001016static bool is_word_sized(struct nct6775_data *data, u16 reg)
1017{
1018 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001019 case nct6106:
1020 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1021 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1022 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001023 case nct6775:
1024 return (((reg & 0xff00) == 0x100 ||
1025 (reg & 0xff00) == 0x200) &&
1026 ((reg & 0x00ff) == 0x50 ||
1027 (reg & 0x00ff) == 0x53 ||
1028 (reg & 0x00ff) == 0x55)) ||
1029 (reg & 0xfff0) == 0x630 ||
1030 reg == 0x640 || reg == 0x642 ||
1031 reg == 0x662 ||
1032 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1033 reg == 0x73 || reg == 0x75 || reg == 0x77;
1034 case nct6776:
1035 return (((reg & 0xff00) == 0x100 ||
1036 (reg & 0xff00) == 0x200) &&
1037 ((reg & 0x00ff) == 0x50 ||
1038 (reg & 0x00ff) == 0x53 ||
1039 (reg & 0x00ff) == 0x55)) ||
1040 (reg & 0xfff0) == 0x630 ||
1041 reg == 0x402 ||
1042 reg == 0x640 || reg == 0x642 ||
1043 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1044 reg == 0x73 || reg == 0x75 || reg == 0x77;
1045 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001046 case nct6791:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001047 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001048 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001049 reg == 0x402 ||
1050 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1051 reg == 0x640 || reg == 0x642 ||
1052 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
1053 reg == 0x7b;
1054 }
1055 return false;
1056}
1057
1058/*
1059 * On older chips, only registers 0x50-0x5f are banked.
1060 * On more recent chips, all registers are banked.
1061 * Assume that is the case and set the bank number for each access.
1062 * Cache the bank number so it only needs to be set if it changes.
1063 */
1064static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1065{
1066 u8 bank = reg >> 8;
1067 if (data->bank != bank) {
1068 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1069 outb_p(bank, data->addr + DATA_REG_OFFSET);
1070 data->bank = bank;
1071 }
1072}
1073
1074static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1075{
1076 int res, word_sized = is_word_sized(data, reg);
1077
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001078 nct6775_set_bank(data, reg);
1079 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1080 res = inb_p(data->addr + DATA_REG_OFFSET);
1081 if (word_sized) {
1082 outb_p((reg & 0xff) + 1,
1083 data->addr + ADDR_REG_OFFSET);
1084 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1085 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001086 return res;
1087}
1088
1089static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1090{
1091 int word_sized = is_word_sized(data, reg);
1092
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001093 nct6775_set_bank(data, reg);
1094 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1095 if (word_sized) {
1096 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1097 outb_p((reg & 0xff) + 1,
1098 data->addr + ADDR_REG_OFFSET);
1099 }
1100 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001101 return 0;
1102}
1103
Guenter Roeckaa136e52012-12-04 03:26:05 -08001104/* We left-align 8-bit temperature values to make the code simpler */
1105static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1106{
1107 u16 res;
1108
1109 res = nct6775_read_value(data, reg);
1110 if (!is_word_sized(data, reg))
1111 res <<= 8;
1112
1113 return res;
1114}
1115
1116static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1117{
1118 if (!is_word_sized(data, reg))
1119 value >>= 8;
1120 return nct6775_write_value(data, reg, value);
1121}
1122
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001123/* This function assumes that the caller holds data->update_lock */
1124static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1125{
1126 u8 reg;
1127
1128 switch (nr) {
1129 case 0:
1130 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1131 | (data->fan_div[0] & 0x7);
1132 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1133 break;
1134 case 1:
1135 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1136 | ((data->fan_div[1] << 4) & 0x70);
1137 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1138 break;
1139 case 2:
1140 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1141 | (data->fan_div[2] & 0x7);
1142 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1143 break;
1144 case 3:
1145 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1146 | ((data->fan_div[3] << 4) & 0x70);
1147 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1148 break;
1149 }
1150}
1151
1152static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1153{
1154 if (data->kind == nct6775)
1155 nct6775_write_fan_div(data, nr);
1156}
1157
1158static void nct6775_update_fan_div(struct nct6775_data *data)
1159{
1160 u8 i;
1161
1162 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1163 data->fan_div[0] = i & 0x7;
1164 data->fan_div[1] = (i & 0x70) >> 4;
1165 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1166 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001167 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001168 data->fan_div[3] = (i & 0x70) >> 4;
1169}
1170
1171static void nct6775_update_fan_div_common(struct nct6775_data *data)
1172{
1173 if (data->kind == nct6775)
1174 nct6775_update_fan_div(data);
1175}
1176
1177static void nct6775_init_fan_div(struct nct6775_data *data)
1178{
1179 int i;
1180
1181 nct6775_update_fan_div_common(data);
1182 /*
1183 * For all fans, start with highest divider value if the divider
1184 * register is not initialized. This ensures that we get a
1185 * reading from the fan count register, even if it is not optimal.
1186 * We'll compute a better divider later on.
1187 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001188 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001189 if (!(data->has_fan & (1 << i)))
1190 continue;
1191 if (data->fan_div[i] == 0) {
1192 data->fan_div[i] = 7;
1193 nct6775_write_fan_div_common(data, i);
1194 }
1195 }
1196}
1197
1198static void nct6775_init_fan_common(struct device *dev,
1199 struct nct6775_data *data)
1200{
1201 int i;
1202 u8 reg;
1203
1204 if (data->has_fan_div)
1205 nct6775_init_fan_div(data);
1206
1207 /*
1208 * If fan_min is not set (0), set it to 0xff to disable it. This
1209 * prevents the unnecessary warning when fanX_min is reported as 0.
1210 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001211 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001212 if (data->has_fan_min & (1 << i)) {
1213 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1214 if (!reg)
1215 nct6775_write_value(data, data->REG_FAN_MIN[i],
1216 data->has_fan_div ? 0xff
1217 : 0xff1f);
1218 }
1219 }
1220}
1221
1222static void nct6775_select_fan_div(struct device *dev,
1223 struct nct6775_data *data, int nr, u16 reg)
1224{
1225 u8 fan_div = data->fan_div[nr];
1226 u16 fan_min;
1227
1228 if (!data->has_fan_div)
1229 return;
1230
1231 /*
1232 * If we failed to measure the fan speed, or the reported value is not
1233 * in the optimal range, and the clock divider can be modified,
1234 * let's try that for next time.
1235 */
1236 if (reg == 0x00 && fan_div < 0x07)
1237 fan_div++;
1238 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1239 fan_div--;
1240
1241 if (fan_div != data->fan_div[nr]) {
1242 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1243 nr + 1, div_from_reg(data->fan_div[nr]),
1244 div_from_reg(fan_div));
1245
1246 /* Preserve min limit if possible */
1247 if (data->has_fan_min & (1 << nr)) {
1248 fan_min = data->fan_min[nr];
1249 if (fan_div > data->fan_div[nr]) {
1250 if (fan_min != 255 && fan_min > 1)
1251 fan_min >>= 1;
1252 } else {
1253 if (fan_min != 255) {
1254 fan_min <<= 1;
1255 if (fan_min > 254)
1256 fan_min = 254;
1257 }
1258 }
1259 if (fan_min != data->fan_min[nr]) {
1260 data->fan_min[nr] = fan_min;
1261 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1262 fan_min);
1263 }
1264 }
1265 data->fan_div[nr] = fan_div;
1266 nct6775_write_fan_div_common(data, nr);
1267 }
1268}
1269
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001270static void nct6775_update_pwm(struct device *dev)
1271{
1272 struct nct6775_data *data = dev_get_drvdata(dev);
1273 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001274 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001275 bool duty_is_dc;
1276
1277 for (i = 0; i < data->pwm_num; i++) {
1278 if (!(data->has_pwm & (1 << i)))
1279 continue;
1280
1281 duty_is_dc = data->REG_PWM_MODE[i] &&
1282 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1283 & data->PWM_MODE_MASK[i]);
1284 data->pwm_mode[i] = duty_is_dc;
1285
1286 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1287 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1288 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1289 data->pwm[j][i]
1290 = nct6775_read_value(data,
1291 data->REG_PWM[j][i]);
1292 }
1293 }
1294
1295 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1296 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001297
1298 if (!data->temp_tolerance[0][i] ||
1299 data->pwm_enable[i] != speed_cruise)
1300 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1301 if (!data->target_speed_tolerance[i] ||
1302 data->pwm_enable[i] == speed_cruise) {
1303 u8 t = fanmodecfg & 0x0f;
1304 if (data->REG_TOLERANCE_H) {
1305 t |= (nct6775_read_value(data,
1306 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1307 }
1308 data->target_speed_tolerance[i] = t;
1309 }
1310
1311 data->temp_tolerance[1][i] =
1312 nct6775_read_value(data,
1313 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1314
1315 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1316 data->pwm_temp_sel[i] = reg & 0x1f;
1317 /* If fan can stop, report floor as 0 */
1318 if (reg & 0x80)
1319 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001320
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001321 if (!data->REG_WEIGHT_TEMP_SEL[i])
1322 continue;
1323
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001324 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1325 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1326 /* If weight is disabled, report weight source as 0 */
1327 if (j == 1 && !(reg & 0x80))
1328 data->pwm_weight_temp_sel[i] = 0;
1329
1330 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001331 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001332 data->weight_temp[j][i]
1333 = nct6775_read_value(data,
1334 data->REG_WEIGHT_TEMP[j][i]);
1335 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001336 }
1337}
1338
1339static void nct6775_update_pwm_limits(struct device *dev)
1340{
1341 struct nct6775_data *data = dev_get_drvdata(dev);
1342 int i, j;
1343 u8 reg;
1344 u16 reg_t;
1345
1346 for (i = 0; i < data->pwm_num; i++) {
1347 if (!(data->has_pwm & (1 << i)))
1348 continue;
1349
Guenter Roeckc409fd42013-04-09 05:04:00 -07001350 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001351 data->fan_time[j][i] =
1352 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1353 }
1354
1355 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1356 /* Update only in matching mode or if never updated */
1357 if (!data->target_temp[i] ||
1358 data->pwm_enable[i] == thermal_cruise)
1359 data->target_temp[i] = reg_t & data->target_temp_mask;
1360 if (!data->target_speed[i] ||
1361 data->pwm_enable[i] == speed_cruise) {
1362 if (data->REG_TOLERANCE_H) {
1363 reg_t |= (nct6775_read_value(data,
1364 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1365 }
1366 data->target_speed[i] = reg_t;
1367 }
1368
1369 for (j = 0; j < data->auto_pwm_num; j++) {
1370 data->auto_pwm[i][j] =
1371 nct6775_read_value(data,
1372 NCT6775_AUTO_PWM(data, i, j));
1373 data->auto_temp[i][j] =
1374 nct6775_read_value(data,
1375 NCT6775_AUTO_TEMP(data, i, j));
1376 }
1377
1378 /* critical auto_pwm temperature data */
1379 data->auto_temp[i][data->auto_pwm_num] =
1380 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1381
1382 switch (data->kind) {
1383 case nct6775:
1384 reg = nct6775_read_value(data,
1385 NCT6775_REG_CRITICAL_ENAB[i]);
1386 data->auto_pwm[i][data->auto_pwm_num] =
1387 (reg & 0x02) ? 0xff : 0x00;
1388 break;
1389 case nct6776:
1390 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1391 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001392 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001393 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001394 case nct6791:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001395 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001396 data->REG_CRITICAL_PWM_ENABLE[i]);
1397 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1398 reg = nct6775_read_value(data,
1399 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001400 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001401 reg = 0xff;
1402 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001403 break;
1404 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001405 }
1406}
1407
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001408static struct nct6775_data *nct6775_update_device(struct device *dev)
1409{
1410 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001411 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001412
1413 mutex_lock(&data->update_lock);
1414
Guenter Roeck6445e662013-04-21 09:13:28 -07001415 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001416 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001417 /* Fan clock dividers */
1418 nct6775_update_fan_div_common(data);
1419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001420 /* Measured voltages and limits */
1421 for (i = 0; i < data->in_num; i++) {
1422 if (!(data->have_in & (1 << i)))
1423 continue;
1424
1425 data->in[i][0] = nct6775_read_value(data,
1426 data->REG_VIN[i]);
1427 data->in[i][1] = nct6775_read_value(data,
1428 data->REG_IN_MINMAX[0][i]);
1429 data->in[i][2] = nct6775_read_value(data,
1430 data->REG_IN_MINMAX[1][i]);
1431 }
1432
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001433 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001434 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001435 u16 reg;
1436
1437 if (!(data->has_fan & (1 << i)))
1438 continue;
1439
1440 reg = nct6775_read_value(data, data->REG_FAN[i]);
1441 data->rpm[i] = data->fan_from_reg(reg,
1442 data->fan_div[i]);
1443
1444 if (data->has_fan_min & (1 << i))
1445 data->fan_min[i] = nct6775_read_value(data,
1446 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001447 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001448 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1449 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001450
1451 nct6775_select_fan_div(dev, data, i, reg);
1452 }
1453
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001454 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001455 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001456
Guenter Roeckaa136e52012-12-04 03:26:05 -08001457 /* Measured temperatures and limits */
1458 for (i = 0; i < NUM_TEMP; i++) {
1459 if (!(data->have_temp & (1 << i)))
1460 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001461 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001462 if (data->reg_temp[j][i])
1463 data->temp[j][i]
1464 = nct6775_read_temp(data,
1465 data->reg_temp[j][i]);
1466 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001467 if (i >= NUM_TEMP_FIXED ||
1468 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001469 continue;
1470 data->temp_offset[i]
1471 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1472 }
1473
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001474 data->alarms = 0;
1475 for (i = 0; i < NUM_REG_ALARM; i++) {
1476 u8 alarm;
1477 if (!data->REG_ALARM[i])
1478 continue;
1479 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1480 data->alarms |= ((u64)alarm) << (i << 3);
1481 }
1482
Guenter Roeck30846992013-06-24 22:21:59 -07001483 data->beeps = 0;
1484 for (i = 0; i < NUM_REG_BEEP; i++) {
1485 u8 beep;
1486 if (!data->REG_BEEP[i])
1487 continue;
1488 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1489 data->beeps |= ((u64)beep) << (i << 3);
1490 }
1491
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001492 data->last_updated = jiffies;
1493 data->valid = true;
1494 }
1495
1496 mutex_unlock(&data->update_lock);
1497 return data;
1498}
1499
1500/*
1501 * Sysfs callback functions
1502 */
1503static ssize_t
1504show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1505{
1506 struct nct6775_data *data = nct6775_update_device(dev);
1507 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1508 int nr = sattr->nr;
1509 int index = sattr->index;
1510 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1511}
1512
1513static ssize_t
1514store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1515 size_t count)
1516{
1517 struct nct6775_data *data = dev_get_drvdata(dev);
1518 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1519 int nr = sattr->nr;
1520 int index = sattr->index;
1521 unsigned long val;
1522 int err = kstrtoul(buf, 10, &val);
1523 if (err < 0)
1524 return err;
1525 mutex_lock(&data->update_lock);
1526 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001527 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001528 data->in[nr][index]);
1529 mutex_unlock(&data->update_lock);
1530 return count;
1531}
1532
1533static ssize_t
1534show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1535{
1536 struct nct6775_data *data = nct6775_update_device(dev);
1537 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1538 int nr = data->ALARM_BITS[sattr->index];
1539 return sprintf(buf, "%u\n",
1540 (unsigned int)((data->alarms >> nr) & 0x01));
1541}
1542
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001543static int find_temp_source(struct nct6775_data *data, int index, int count)
1544{
1545 int source = data->temp_src[index];
1546 int nr;
1547
1548 for (nr = 0; nr < count; nr++) {
1549 int src;
1550
1551 src = nct6775_read_value(data,
1552 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1553 if (src == source)
1554 return nr;
1555 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001556 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001557}
1558
1559static ssize_t
1560show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1561{
1562 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1563 struct nct6775_data *data = nct6775_update_device(dev);
1564 unsigned int alarm = 0;
1565 int nr;
1566
1567 /*
1568 * For temperatures, there is no fixed mapping from registers to alarm
1569 * bits. Alarm bits are determined by the temperature source mapping.
1570 */
1571 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1572 if (nr >= 0) {
1573 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
1574 alarm = (data->alarms >> bit) & 0x01;
1575 }
1576 return sprintf(buf, "%u\n", alarm);
1577}
1578
Guenter Roeck30846992013-06-24 22:21:59 -07001579static ssize_t
1580show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1581{
1582 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1583 struct nct6775_data *data = nct6775_update_device(dev);
1584 int nr = data->BEEP_BITS[sattr->index];
1585
1586 return sprintf(buf, "%u\n",
1587 (unsigned int)((data->beeps >> nr) & 0x01));
1588}
1589
1590static ssize_t
1591store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1592 size_t count)
1593{
1594 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1595 struct nct6775_data *data = dev_get_drvdata(dev);
1596 int nr = data->BEEP_BITS[sattr->index];
1597 int regindex = nr >> 3;
1598 unsigned long val;
1599
1600 int err = kstrtoul(buf, 10, &val);
1601 if (err < 0)
1602 return err;
1603 if (val > 1)
1604 return -EINVAL;
1605
1606 mutex_lock(&data->update_lock);
1607 if (val)
1608 data->beeps |= (1ULL << nr);
1609 else
1610 data->beeps &= ~(1ULL << nr);
1611 nct6775_write_value(data, data->REG_BEEP[regindex],
1612 (data->beeps >> (regindex << 3)) & 0xff);
1613 mutex_unlock(&data->update_lock);
1614 return count;
1615}
1616
1617static ssize_t
1618show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1619{
1620 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1621 struct nct6775_data *data = nct6775_update_device(dev);
1622 unsigned int beep = 0;
1623 int nr;
1624
1625 /*
1626 * For temperatures, there is no fixed mapping from registers to beep
1627 * enable bits. Beep enable bits are determined by the temperature
1628 * source mapping.
1629 */
1630 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1631 if (nr >= 0) {
1632 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1633 beep = (data->beeps >> bit) & 0x01;
1634 }
1635 return sprintf(buf, "%u\n", beep);
1636}
1637
1638static ssize_t
1639store_temp_beep(struct device *dev, struct device_attribute *attr,
1640 const char *buf, size_t count)
1641{
1642 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1643 struct nct6775_data *data = dev_get_drvdata(dev);
1644 int nr, bit, regindex;
1645 unsigned long val;
1646
1647 int err = kstrtoul(buf, 10, &val);
1648 if (err < 0)
1649 return err;
1650 if (val > 1)
1651 return -EINVAL;
1652
1653 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1654 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001655 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001656
1657 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1658 regindex = bit >> 3;
1659
1660 mutex_lock(&data->update_lock);
1661 if (val)
1662 data->beeps |= (1ULL << bit);
1663 else
1664 data->beeps &= ~(1ULL << bit);
1665 nct6775_write_value(data, data->REG_BEEP[regindex],
1666 (data->beeps >> (regindex << 3)) & 0xff);
1667 mutex_unlock(&data->update_lock);
1668
1669 return count;
1670}
1671
Guenter Roeckf73cf632013-03-18 09:22:50 -07001672static umode_t nct6775_in_is_visible(struct kobject *kobj,
1673 struct attribute *attr, int index)
1674{
1675 struct device *dev = container_of(kobj, struct device, kobj);
1676 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001677 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001678
Guenter Roeckf73cf632013-03-18 09:22:50 -07001679 if (!(data->have_in & (1 << in)))
1680 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001681
Guenter Roeckf73cf632013-03-18 09:22:50 -07001682 return attr->mode;
1683}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001684
Guenter Roeckf73cf632013-03-18 09:22:50 -07001685SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1686SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001687SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1688 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001689SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1690 store_in_reg, 0, 1);
1691SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1692 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001693
Guenter Roeckf73cf632013-03-18 09:22:50 -07001694/*
1695 * nct6775_in_is_visible uses the index into the following array
1696 * to determine if attributes should be created or not.
1697 * Any change in order or content must be matched.
1698 */
1699static struct sensor_device_template *nct6775_attributes_in_template[] = {
1700 &sensor_dev_template_in_input,
1701 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001702 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001703 &sensor_dev_template_in_min,
1704 &sensor_dev_template_in_max,
1705 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001706};
1707
Guenter Roeckf73cf632013-03-18 09:22:50 -07001708static struct sensor_template_group nct6775_in_template_group = {
1709 .templates = nct6775_attributes_in_template,
1710 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001711};
1712
1713static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001714show_fan(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", data->rpm[nr]);
1720}
1721
1722static ssize_t
1723show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1724{
1725 struct nct6775_data *data = nct6775_update_device(dev);
1726 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1727 int nr = sattr->index;
1728 return sprintf(buf, "%d\n",
1729 data->fan_from_reg_min(data->fan_min[nr],
1730 data->fan_div[nr]));
1731}
1732
1733static ssize_t
1734show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1735{
1736 struct nct6775_data *data = nct6775_update_device(dev);
1737 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1738 int nr = sattr->index;
1739 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1740}
1741
1742static ssize_t
1743store_fan_min(struct device *dev, struct device_attribute *attr,
1744 const char *buf, size_t count)
1745{
1746 struct nct6775_data *data = dev_get_drvdata(dev);
1747 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1748 int nr = sattr->index;
1749 unsigned long val;
1750 int err;
1751 unsigned int reg;
1752 u8 new_div;
1753
1754 err = kstrtoul(buf, 10, &val);
1755 if (err < 0)
1756 return err;
1757
1758 mutex_lock(&data->update_lock);
1759 if (!data->has_fan_div) {
1760 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1761 if (!val) {
1762 val = 0xff1f;
1763 } else {
1764 if (val > 1350000U)
1765 val = 135000U;
1766 val = 1350000U / val;
1767 val = (val & 0x1f) | ((val << 3) & 0xff00);
1768 }
1769 data->fan_min[nr] = val;
1770 goto write_min; /* Leave fan divider alone */
1771 }
1772 if (!val) {
1773 /* No min limit, alarm disabled */
1774 data->fan_min[nr] = 255;
1775 new_div = data->fan_div[nr]; /* No change */
1776 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1777 goto write_div;
1778 }
1779 reg = 1350000U / val;
1780 if (reg >= 128 * 255) {
1781 /*
1782 * Speed below this value cannot possibly be represented,
1783 * even with the highest divider (128)
1784 */
1785 data->fan_min[nr] = 254;
1786 new_div = 7; /* 128 == (1 << 7) */
1787 dev_warn(dev,
1788 "fan%u low limit %lu below minimum %u, set to minimum\n",
1789 nr + 1, val, data->fan_from_reg_min(254, 7));
1790 } else if (!reg) {
1791 /*
1792 * Speed above this value cannot possibly be represented,
1793 * even with the lowest divider (1)
1794 */
1795 data->fan_min[nr] = 1;
1796 new_div = 0; /* 1 == (1 << 0) */
1797 dev_warn(dev,
1798 "fan%u low limit %lu above maximum %u, set to maximum\n",
1799 nr + 1, val, data->fan_from_reg_min(1, 0));
1800 } else {
1801 /*
1802 * Automatically pick the best divider, i.e. the one such
1803 * that the min limit will correspond to a register value
1804 * in the 96..192 range
1805 */
1806 new_div = 0;
1807 while (reg > 192 && new_div < 7) {
1808 reg >>= 1;
1809 new_div++;
1810 }
1811 data->fan_min[nr] = reg;
1812 }
1813
1814write_div:
1815 /*
1816 * Write both the fan clock divider (if it changed) and the new
1817 * fan min (unconditionally)
1818 */
1819 if (new_div != data->fan_div[nr]) {
1820 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1821 nr + 1, div_from_reg(data->fan_div[nr]),
1822 div_from_reg(new_div));
1823 data->fan_div[nr] = new_div;
1824 nct6775_write_fan_div_common(data, nr);
1825 /* Give the chip time to sample a new speed value */
1826 data->last_updated = jiffies;
1827 }
1828
1829write_min:
1830 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1831 mutex_unlock(&data->update_lock);
1832
1833 return count;
1834}
1835
Guenter Roeck5c25d952012-12-11 07:29:06 -08001836static ssize_t
1837show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1838{
1839 struct nct6775_data *data = nct6775_update_device(dev);
1840 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1841 int p = data->fan_pulses[sattr->index];
1842
1843 return sprintf(buf, "%d\n", p ? : 4);
1844}
1845
1846static ssize_t
1847store_fan_pulses(struct device *dev, struct device_attribute *attr,
1848 const char *buf, size_t count)
1849{
1850 struct nct6775_data *data = dev_get_drvdata(dev);
1851 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1852 int nr = sattr->index;
1853 unsigned long val;
1854 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001855 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001856
1857 err = kstrtoul(buf, 10, &val);
1858 if (err < 0)
1859 return err;
1860
1861 if (val > 4)
1862 return -EINVAL;
1863
1864 mutex_lock(&data->update_lock);
1865 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001866 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1867 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1868 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1869 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001870 mutex_unlock(&data->update_lock);
1871
1872 return count;
1873}
1874
Guenter Roeckf73cf632013-03-18 09:22:50 -07001875static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1876 struct attribute *attr, int index)
1877{
1878 struct device *dev = container_of(kobj, struct device, kobj);
1879 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001880 int fan = index / 6; /* fan index */
1881 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001882
1883 if (!(data->has_fan & (1 << fan)))
1884 return 0;
1885
1886 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1887 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001888 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001889 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001890 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1891 return 0;
1892 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001893 return 0;
1894
1895 return attr->mode;
1896}
1897
1898SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1899SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1900 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001901SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1902 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001903SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1904 store_fan_pulses, 0);
1905SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1906 store_fan_min, 0);
1907SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1908
1909/*
1910 * nct6775_fan_is_visible uses the index into the following array
1911 * to determine if attributes should be created or not.
1912 * Any change in order or content must be matched.
1913 */
1914static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1915 &sensor_dev_template_fan_input,
1916 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001917 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001918 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001919 &sensor_dev_template_fan_min, /* 4 */
1920 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001921 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001922};
1923
Guenter Roeckf73cf632013-03-18 09:22:50 -07001924static struct sensor_template_group nct6775_fan_template_group = {
1925 .templates = nct6775_attributes_fan_template,
1926 .is_visible = nct6775_fan_is_visible,
1927 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001928};
1929
1930static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001931show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1932{
1933 struct nct6775_data *data = nct6775_update_device(dev);
1934 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1935 int nr = sattr->index;
1936 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1937}
1938
1939static ssize_t
1940show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1941{
1942 struct nct6775_data *data = nct6775_update_device(dev);
1943 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1944 int nr = sattr->nr;
1945 int index = sattr->index;
1946
1947 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1948}
1949
1950static ssize_t
1951store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1952 size_t count)
1953{
1954 struct nct6775_data *data = dev_get_drvdata(dev);
1955 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1956 int nr = sattr->nr;
1957 int index = sattr->index;
1958 int err;
1959 long val;
1960
1961 err = kstrtol(buf, 10, &val);
1962 if (err < 0)
1963 return err;
1964
1965 mutex_lock(&data->update_lock);
1966 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
1967 nct6775_write_temp(data, data->reg_temp[index][nr],
1968 data->temp[index][nr]);
1969 mutex_unlock(&data->update_lock);
1970 return count;
1971}
1972
1973static ssize_t
1974show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
1975{
1976 struct nct6775_data *data = nct6775_update_device(dev);
1977 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1978
1979 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
1980}
1981
1982static ssize_t
1983store_temp_offset(struct device *dev, struct device_attribute *attr,
1984 const char *buf, size_t count)
1985{
1986 struct nct6775_data *data = dev_get_drvdata(dev);
1987 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1988 int nr = sattr->index;
1989 long val;
1990 int err;
1991
1992 err = kstrtol(buf, 10, &val);
1993 if (err < 0)
1994 return err;
1995
1996 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
1997
1998 mutex_lock(&data->update_lock);
1999 data->temp_offset[nr] = val;
2000 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2001 mutex_unlock(&data->update_lock);
2002
2003 return count;
2004}
2005
2006static ssize_t
2007show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2008{
2009 struct nct6775_data *data = nct6775_update_device(dev);
2010 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2011 int nr = sattr->index;
2012 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2013}
2014
2015static ssize_t
2016store_temp_type(struct device *dev, struct device_attribute *attr,
2017 const char *buf, size_t count)
2018{
2019 struct nct6775_data *data = nct6775_update_device(dev);
2020 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2021 int nr = sattr->index;
2022 unsigned long val;
2023 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002024 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002025
2026 err = kstrtoul(buf, 10, &val);
2027 if (err < 0)
2028 return err;
2029
2030 if (val != 1 && val != 3 && val != 4)
2031 return -EINVAL;
2032
2033 mutex_lock(&data->update_lock);
2034
2035 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002036 vbit = 0x02 << nr;
2037 dbit = data->DIODE_MASK << nr;
2038 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2039 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002040 switch (val) {
2041 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002042 vbat |= vbit;
2043 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002044 break;
2045 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002046 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002047 break;
2048 case 4: /* thermistor */
2049 break;
2050 }
2051 nct6775_write_value(data, data->REG_VBAT, vbat);
2052 nct6775_write_value(data, data->REG_DIODE, diode);
2053
2054 mutex_unlock(&data->update_lock);
2055 return count;
2056}
2057
Guenter Roeckf73cf632013-03-18 09:22:50 -07002058static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2059 struct attribute *attr, int index)
2060{
2061 struct device *dev = container_of(kobj, struct device, kobj);
2062 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002063 int temp = index / 10; /* temp index */
2064 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002065
2066 if (!(data->have_temp & (1 << temp)))
2067 return 0;
2068
2069 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2070 return 0; /* alarm */
2071
Guenter Roeck30846992013-06-24 22:21:59 -07002072 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2073 return 0; /* beep */
2074
2075 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002076 return 0;
2077
Guenter Roeck30846992013-06-24 22:21:59 -07002078 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002079 return 0;
2080
Guenter Roeck30846992013-06-24 22:21:59 -07002081 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002082 return 0;
2083
Guenter Roeck30846992013-06-24 22:21:59 -07002084 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002085 return 0;
2086
2087 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002088 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002089 return 0;
2090
2091 return attr->mode;
2092}
2093
2094SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2095SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2096SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2097 store_temp, 0, 1);
2098SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2099 show_temp, store_temp, 0, 2);
2100SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2101 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002102SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2103 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002104SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2105 show_temp_offset, store_temp_offset, 0);
2106SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2107 store_temp_type, 0);
2108SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002109SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2110 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002111
2112/*
2113 * nct6775_temp_is_visible uses the index into the following array
2114 * to determine if attributes should be created or not.
2115 * Any change in order or content must be matched.
2116 */
2117static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2118 &sensor_dev_template_temp_input,
2119 &sensor_dev_template_temp_label,
2120 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002121 &sensor_dev_template_temp_beep, /* 3 */
2122 &sensor_dev_template_temp_max, /* 4 */
2123 &sensor_dev_template_temp_max_hyst, /* 5 */
2124 &sensor_dev_template_temp_crit, /* 6 */
2125 &sensor_dev_template_temp_lcrit, /* 7 */
2126 &sensor_dev_template_temp_offset, /* 8 */
2127 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002128 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002129};
2130
Guenter Roeckf73cf632013-03-18 09:22:50 -07002131static struct sensor_template_group nct6775_temp_template_group = {
2132 .templates = nct6775_attributes_temp_template,
2133 .is_visible = nct6775_temp_is_visible,
2134 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002135};
2136
Guenter Roeckaa136e52012-12-04 03:26:05 -08002137static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002138show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2139{
2140 struct nct6775_data *data = nct6775_update_device(dev);
2141 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2142
2143 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2144}
2145
2146static ssize_t
2147store_pwm_mode(struct device *dev, struct device_attribute *attr,
2148 const char *buf, size_t count)
2149{
2150 struct nct6775_data *data = dev_get_drvdata(dev);
2151 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2152 int nr = sattr->index;
2153 unsigned long val;
2154 int err;
2155 u8 reg;
2156
2157 err = kstrtoul(buf, 10, &val);
2158 if (err < 0)
2159 return err;
2160
2161 if (val > 1)
2162 return -EINVAL;
2163
2164 /* Setting DC mode is not supported for all chips/channels */
2165 if (data->REG_PWM_MODE[nr] == 0) {
2166 if (val)
2167 return -EINVAL;
2168 return count;
2169 }
2170
2171 mutex_lock(&data->update_lock);
2172 data->pwm_mode[nr] = val;
2173 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2174 reg &= ~data->PWM_MODE_MASK[nr];
2175 if (val)
2176 reg |= data->PWM_MODE_MASK[nr];
2177 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2178 mutex_unlock(&data->update_lock);
2179 return count;
2180}
2181
2182static ssize_t
2183show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2184{
2185 struct nct6775_data *data = nct6775_update_device(dev);
2186 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2187 int nr = sattr->nr;
2188 int index = sattr->index;
2189 int pwm;
2190
2191 /*
2192 * For automatic fan control modes, show current pwm readings.
2193 * Otherwise, show the configured value.
2194 */
2195 if (index == 0 && data->pwm_enable[nr] > manual)
2196 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2197 else
2198 pwm = data->pwm[index][nr];
2199
2200 return sprintf(buf, "%d\n", pwm);
2201}
2202
2203static ssize_t
2204store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2205 size_t count)
2206{
2207 struct nct6775_data *data = dev_get_drvdata(dev);
2208 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2209 int nr = sattr->nr;
2210 int index = sattr->index;
2211 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002212 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2213 int maxval[7]
2214 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002215 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002216 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002217
2218 err = kstrtoul(buf, 10, &val);
2219 if (err < 0)
2220 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002221 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002222
2223 mutex_lock(&data->update_lock);
2224 data->pwm[index][nr] = val;
2225 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002226 if (index == 2) { /* floor: disable if val == 0 */
2227 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2228 reg &= 0x7f;
2229 if (val)
2230 reg |= 0x80;
2231 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2232 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002233 mutex_unlock(&data->update_lock);
2234 return count;
2235}
2236
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002237/* Returns 0 if OK, -EINVAL otherwise */
2238static int check_trip_points(struct nct6775_data *data, int nr)
2239{
2240 int i;
2241
2242 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2243 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2244 return -EINVAL;
2245 }
2246 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2247 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2248 return -EINVAL;
2249 }
2250 /* validate critical temperature and pwm if enabled (pwm > 0) */
2251 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2252 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2253 data->auto_temp[nr][data->auto_pwm_num] ||
2254 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2255 data->auto_pwm[nr][data->auto_pwm_num])
2256 return -EINVAL;
2257 }
2258 return 0;
2259}
2260
2261static void pwm_update_registers(struct nct6775_data *data, int nr)
2262{
2263 u8 reg;
2264
2265 switch (data->pwm_enable[nr]) {
2266 case off:
2267 case manual:
2268 break;
2269 case speed_cruise:
2270 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2271 reg = (reg & ~data->tolerance_mask) |
2272 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2273 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2274 nct6775_write_value(data, data->REG_TARGET[nr],
2275 data->target_speed[nr] & 0xff);
2276 if (data->REG_TOLERANCE_H) {
2277 reg = (data->target_speed[nr] >> 8) & 0x0f;
2278 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2279 nct6775_write_value(data,
2280 data->REG_TOLERANCE_H[nr],
2281 reg);
2282 }
2283 break;
2284 case thermal_cruise:
2285 nct6775_write_value(data, data->REG_TARGET[nr],
2286 data->target_temp[nr]);
2287 /* intentional */
2288 default:
2289 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2290 reg = (reg & ~data->tolerance_mask) |
2291 data->temp_tolerance[0][nr];
2292 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2293 break;
2294 }
2295}
2296
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002297static ssize_t
2298show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2299{
2300 struct nct6775_data *data = nct6775_update_device(dev);
2301 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2302
2303 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2304}
2305
2306static ssize_t
2307store_pwm_enable(struct device *dev, struct device_attribute *attr,
2308 const char *buf, size_t count)
2309{
2310 struct nct6775_data *data = dev_get_drvdata(dev);
2311 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2312 int nr = sattr->index;
2313 unsigned long val;
2314 int err;
2315 u16 reg;
2316
2317 err = kstrtoul(buf, 10, &val);
2318 if (err < 0)
2319 return err;
2320
2321 if (val > sf4)
2322 return -EINVAL;
2323
2324 if (val == sf3 && data->kind != nct6775)
2325 return -EINVAL;
2326
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002327 if (val == sf4 && check_trip_points(data, nr)) {
2328 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2329 dev_err(dev, "Adjust trip points and try again\n");
2330 return -EINVAL;
2331 }
2332
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002333 mutex_lock(&data->update_lock);
2334 data->pwm_enable[nr] = val;
2335 if (val == off) {
2336 /*
2337 * turn off pwm control: select manual mode, set pwm to maximum
2338 */
2339 data->pwm[0][nr] = 255;
2340 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2341 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002342 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002343 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2344 reg &= 0x0f;
2345 reg |= pwm_enable_to_reg(val) << 4;
2346 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2347 mutex_unlock(&data->update_lock);
2348 return count;
2349}
2350
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002351static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002352show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002353{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002354 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002355
2356 for (i = 0; i < NUM_TEMP; i++) {
2357 if (!(data->have_temp & (1 << i)))
2358 continue;
2359 if (src == data->temp_src[i]) {
2360 sel = i + 1;
2361 break;
2362 }
2363 }
2364
2365 return sprintf(buf, "%d\n", sel);
2366}
2367
2368static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002369show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2370{
2371 struct nct6775_data *data = nct6775_update_device(dev);
2372 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2373 int index = sattr->index;
2374
2375 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2376}
2377
2378static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002379store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2380 const char *buf, size_t count)
2381{
2382 struct nct6775_data *data = nct6775_update_device(dev);
2383 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2384 int nr = sattr->index;
2385 unsigned long val;
2386 int err, reg, src;
2387
2388 err = kstrtoul(buf, 10, &val);
2389 if (err < 0)
2390 return err;
2391 if (val == 0 || val > NUM_TEMP)
2392 return -EINVAL;
2393 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2394 return -EINVAL;
2395
2396 mutex_lock(&data->update_lock);
2397 src = data->temp_src[val - 1];
2398 data->pwm_temp_sel[nr] = src;
2399 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2400 reg &= 0xe0;
2401 reg |= src;
2402 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2403 mutex_unlock(&data->update_lock);
2404
2405 return count;
2406}
2407
2408static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002409show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2410 char *buf)
2411{
2412 struct nct6775_data *data = nct6775_update_device(dev);
2413 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2414 int index = sattr->index;
2415
2416 return show_pwm_temp_sel_common(data, buf,
2417 data->pwm_weight_temp_sel[index]);
2418}
2419
2420static ssize_t
2421store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2422 const char *buf, size_t count)
2423{
2424 struct nct6775_data *data = nct6775_update_device(dev);
2425 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2426 int nr = sattr->index;
2427 unsigned long val;
2428 int err, reg, src;
2429
2430 err = kstrtoul(buf, 10, &val);
2431 if (err < 0)
2432 return err;
2433 if (val > NUM_TEMP)
2434 return -EINVAL;
2435 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2436 !data->temp_src[val - 1]))
2437 return -EINVAL;
2438
2439 mutex_lock(&data->update_lock);
2440 if (val) {
2441 src = data->temp_src[val - 1];
2442 data->pwm_weight_temp_sel[nr] = src;
2443 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2444 reg &= 0xe0;
2445 reg |= (src | 0x80);
2446 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2447 } else {
2448 data->pwm_weight_temp_sel[nr] = 0;
2449 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2450 reg &= 0x7f;
2451 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2452 }
2453 mutex_unlock(&data->update_lock);
2454
2455 return count;
2456}
2457
2458static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002459show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2460{
2461 struct nct6775_data *data = nct6775_update_device(dev);
2462 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2463
2464 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2465}
2466
2467static ssize_t
2468store_target_temp(struct device *dev, struct device_attribute *attr,
2469 const char *buf, size_t count)
2470{
2471 struct nct6775_data *data = dev_get_drvdata(dev);
2472 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2473 int nr = sattr->index;
2474 unsigned long val;
2475 int err;
2476
2477 err = kstrtoul(buf, 10, &val);
2478 if (err < 0)
2479 return err;
2480
2481 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2482 data->target_temp_mask);
2483
2484 mutex_lock(&data->update_lock);
2485 data->target_temp[nr] = val;
2486 pwm_update_registers(data, nr);
2487 mutex_unlock(&data->update_lock);
2488 return count;
2489}
2490
2491static ssize_t
2492show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2493{
2494 struct nct6775_data *data = nct6775_update_device(dev);
2495 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2496 int nr = sattr->index;
2497
2498 return sprintf(buf, "%d\n",
2499 fan_from_reg16(data->target_speed[nr],
2500 data->fan_div[nr]));
2501}
2502
2503static ssize_t
2504store_target_speed(struct device *dev, struct device_attribute *attr,
2505 const char *buf, size_t count)
2506{
2507 struct nct6775_data *data = dev_get_drvdata(dev);
2508 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2509 int nr = sattr->index;
2510 unsigned long val;
2511 int err;
2512 u16 speed;
2513
2514 err = kstrtoul(buf, 10, &val);
2515 if (err < 0)
2516 return err;
2517
2518 val = clamp_val(val, 0, 1350000U);
2519 speed = fan_to_reg(val, data->fan_div[nr]);
2520
2521 mutex_lock(&data->update_lock);
2522 data->target_speed[nr] = speed;
2523 pwm_update_registers(data, nr);
2524 mutex_unlock(&data->update_lock);
2525 return count;
2526}
2527
2528static ssize_t
2529show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2530 char *buf)
2531{
2532 struct nct6775_data *data = nct6775_update_device(dev);
2533 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2534 int nr = sattr->nr;
2535 int index = sattr->index;
2536
2537 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2538}
2539
2540static ssize_t
2541store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2542 const char *buf, size_t count)
2543{
2544 struct nct6775_data *data = dev_get_drvdata(dev);
2545 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2546 int nr = sattr->nr;
2547 int index = sattr->index;
2548 unsigned long val;
2549 int err;
2550
2551 err = kstrtoul(buf, 10, &val);
2552 if (err < 0)
2553 return err;
2554
2555 /* Limit tolerance as needed */
2556 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2557
2558 mutex_lock(&data->update_lock);
2559 data->temp_tolerance[index][nr] = val;
2560 if (index)
2561 pwm_update_registers(data, nr);
2562 else
2563 nct6775_write_value(data,
2564 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2565 val);
2566 mutex_unlock(&data->update_lock);
2567 return count;
2568}
2569
2570/*
2571 * Fan speed tolerance is a tricky beast, since the associated register is
2572 * a tick counter, but the value is reported and configured as rpm.
2573 * Compute resulting low and high rpm values and report the difference.
2574 */
2575static ssize_t
2576show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2577 char *buf)
2578{
2579 struct nct6775_data *data = nct6775_update_device(dev);
2580 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2581 int nr = sattr->index;
2582 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2583 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2584 int tolerance;
2585
2586 if (low <= 0)
2587 low = 1;
2588 if (high > 0xffff)
2589 high = 0xffff;
2590 if (high < low)
2591 high = low;
2592
2593 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2594 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2595
2596 return sprintf(buf, "%d\n", tolerance);
2597}
2598
2599static ssize_t
2600store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2601 const char *buf, size_t count)
2602{
2603 struct nct6775_data *data = dev_get_drvdata(dev);
2604 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2605 int nr = sattr->index;
2606 unsigned long val;
2607 int err;
2608 int low, high;
2609
2610 err = kstrtoul(buf, 10, &val);
2611 if (err < 0)
2612 return err;
2613
2614 high = fan_from_reg16(data->target_speed[nr],
2615 data->fan_div[nr]) + val;
2616 low = fan_from_reg16(data->target_speed[nr],
2617 data->fan_div[nr]) - val;
2618 if (low <= 0)
2619 low = 1;
2620 if (high < low)
2621 high = low;
2622
2623 val = (fan_to_reg(low, data->fan_div[nr]) -
2624 fan_to_reg(high, data->fan_div[nr])) / 2;
2625
2626 /* Limit tolerance as needed */
2627 val = clamp_val(val, 0, data->speed_tolerance_limit);
2628
2629 mutex_lock(&data->update_lock);
2630 data->target_speed_tolerance[nr] = val;
2631 pwm_update_registers(data, nr);
2632 mutex_unlock(&data->update_lock);
2633 return count;
2634}
2635
Guenter Roeckf73cf632013-03-18 09:22:50 -07002636SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2637SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2638 store_pwm_mode, 0);
2639SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2640 store_pwm_enable, 0);
2641SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2642 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2643SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2644 show_target_temp, store_target_temp, 0);
2645SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2646 show_target_speed, store_target_speed, 0);
2647SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2648 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002649
2650/* Smart Fan registers */
2651
2652static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002653show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2654{
2655 struct nct6775_data *data = nct6775_update_device(dev);
2656 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2657 int nr = sattr->nr;
2658 int index = sattr->index;
2659
2660 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2661}
2662
2663static ssize_t
2664store_weight_temp(struct device *dev, struct device_attribute *attr,
2665 const char *buf, size_t count)
2666{
2667 struct nct6775_data *data = dev_get_drvdata(dev);
2668 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2669 int nr = sattr->nr;
2670 int index = sattr->index;
2671 unsigned long val;
2672 int err;
2673
2674 err = kstrtoul(buf, 10, &val);
2675 if (err < 0)
2676 return err;
2677
2678 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2679
2680 mutex_lock(&data->update_lock);
2681 data->weight_temp[index][nr] = val;
2682 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2683 mutex_unlock(&data->update_lock);
2684 return count;
2685}
2686
Guenter Roeckf73cf632013-03-18 09:22:50 -07002687SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2688 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2689SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2690 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2691SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2692 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2693SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2694 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2695SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2696 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2697SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2698 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002699
2700static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002701show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2702{
2703 struct nct6775_data *data = nct6775_update_device(dev);
2704 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2705 int nr = sattr->nr;
2706 int index = sattr->index;
2707
2708 return sprintf(buf, "%d\n",
2709 step_time_from_reg(data->fan_time[index][nr],
2710 data->pwm_mode[nr]));
2711}
2712
2713static ssize_t
2714store_fan_time(struct device *dev, struct device_attribute *attr,
2715 const char *buf, size_t count)
2716{
2717 struct nct6775_data *data = dev_get_drvdata(dev);
2718 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2719 int nr = sattr->nr;
2720 int index = sattr->index;
2721 unsigned long val;
2722 int err;
2723
2724 err = kstrtoul(buf, 10, &val);
2725 if (err < 0)
2726 return err;
2727
2728 val = step_time_to_reg(val, data->pwm_mode[nr]);
2729 mutex_lock(&data->update_lock);
2730 data->fan_time[index][nr] = val;
2731 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2732 mutex_unlock(&data->update_lock);
2733 return count;
2734}
2735
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002736static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002737show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2738{
2739 struct nct6775_data *data = nct6775_update_device(dev);
2740 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2741
2742 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2743}
2744
2745static ssize_t
2746store_auto_pwm(struct device *dev, struct device_attribute *attr,
2747 const char *buf, size_t count)
2748{
2749 struct nct6775_data *data = dev_get_drvdata(dev);
2750 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2751 int nr = sattr->nr;
2752 int point = sattr->index;
2753 unsigned long val;
2754 int err;
2755 u8 reg;
2756
2757 err = kstrtoul(buf, 10, &val);
2758 if (err < 0)
2759 return err;
2760 if (val > 255)
2761 return -EINVAL;
2762
2763 if (point == data->auto_pwm_num) {
2764 if (data->kind != nct6775 && !val)
2765 return -EINVAL;
2766 if (data->kind != nct6779 && val)
2767 val = 0xff;
2768 }
2769
2770 mutex_lock(&data->update_lock);
2771 data->auto_pwm[nr][point] = val;
2772 if (point < data->auto_pwm_num) {
2773 nct6775_write_value(data,
2774 NCT6775_AUTO_PWM(data, nr, point),
2775 data->auto_pwm[nr][point]);
2776 } else {
2777 switch (data->kind) {
2778 case nct6775:
2779 /* disable if needed (pwm == 0) */
2780 reg = nct6775_read_value(data,
2781 NCT6775_REG_CRITICAL_ENAB[nr]);
2782 if (val)
2783 reg |= 0x02;
2784 else
2785 reg &= ~0x02;
2786 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2787 reg);
2788 break;
2789 case nct6776:
2790 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002791 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002792 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002793 case nct6791:
Guenter Roeck6c009502012-07-01 08:23:15 -07002794 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002795 val);
2796 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002797 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002798 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002799 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002800 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002801 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002802 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002803 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002804 reg);
2805 break;
2806 }
2807 }
2808 mutex_unlock(&data->update_lock);
2809 return count;
2810}
2811
2812static ssize_t
2813show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2814{
2815 struct nct6775_data *data = nct6775_update_device(dev);
2816 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2817 int nr = sattr->nr;
2818 int point = sattr->index;
2819
2820 /*
2821 * We don't know for sure if the temperature is signed or unsigned.
2822 * Assume it is unsigned.
2823 */
2824 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2825}
2826
2827static ssize_t
2828store_auto_temp(struct device *dev, struct device_attribute *attr,
2829 const char *buf, size_t count)
2830{
2831 struct nct6775_data *data = dev_get_drvdata(dev);
2832 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2833 int nr = sattr->nr;
2834 int point = sattr->index;
2835 unsigned long val;
2836 int err;
2837
2838 err = kstrtoul(buf, 10, &val);
2839 if (err)
2840 return err;
2841 if (val > 255000)
2842 return -EINVAL;
2843
2844 mutex_lock(&data->update_lock);
2845 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2846 if (point < data->auto_pwm_num) {
2847 nct6775_write_value(data,
2848 NCT6775_AUTO_TEMP(data, nr, point),
2849 data->auto_temp[nr][point]);
2850 } else {
2851 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2852 data->auto_temp[nr][point]);
2853 }
2854 mutex_unlock(&data->update_lock);
2855 return count;
2856}
2857
Guenter Roeckf73cf632013-03-18 09:22:50 -07002858static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2859 struct attribute *attr, int index)
2860{
2861 struct device *dev = container_of(kobj, struct device, kobj);
2862 struct nct6775_data *data = dev_get_drvdata(dev);
2863 int pwm = index / 36; /* pwm index */
2864 int nr = index % 36; /* attribute index */
2865
2866 if (!(data->has_pwm & (1 << pwm)))
2867 return 0;
2868
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002869 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2870 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2871 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002872 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2873 return 0;
2874 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2875 return 0;
2876 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2877 return 0;
2878
2879 if (nr >= 22 && nr <= 35) { /* auto point */
2880 int api = (nr - 22) / 2; /* auto point index */
2881
2882 if (api > data->auto_pwm_num)
2883 return 0;
2884 }
2885 return attr->mode;
2886}
2887
2888SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2889 show_fan_time, store_fan_time, 0, 0);
2890SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2891 show_fan_time, store_fan_time, 0, 1);
2892SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2893 show_fan_time, store_fan_time, 0, 2);
2894SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2895 store_pwm, 0, 1);
2896SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2897 store_pwm, 0, 2);
2898SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2899 show_temp_tolerance, store_temp_tolerance, 0, 0);
2900SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2901 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2902 0, 1);
2903
2904SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2905 0, 3);
2906
2907SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2908 store_pwm, 0, 4);
2909
2910SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2911 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2912SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2913 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2914
2915SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2916 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2917SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2918 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2919
2920SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2921 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2922SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2923 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2924
2925SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2926 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2927SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2928 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2929
2930SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2931 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2932SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2933 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2934
2935SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2936 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2937SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2938 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2939
2940SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2941 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2942SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2943 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2944
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002945/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002946 * nct6775_pwm_is_visible uses the index into the following array
2947 * to determine if attributes should be created or not.
2948 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002949 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002950static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2951 &sensor_dev_template_pwm,
2952 &sensor_dev_template_pwm_mode,
2953 &sensor_dev_template_pwm_enable,
2954 &sensor_dev_template_pwm_temp_sel,
2955 &sensor_dev_template_pwm_temp_tolerance,
2956 &sensor_dev_template_pwm_crit_temp_tolerance,
2957 &sensor_dev_template_pwm_target_temp,
2958 &sensor_dev_template_fan_target,
2959 &sensor_dev_template_fan_tolerance,
2960 &sensor_dev_template_pwm_stop_time,
2961 &sensor_dev_template_pwm_step_up_time,
2962 &sensor_dev_template_pwm_step_down_time,
2963 &sensor_dev_template_pwm_start,
2964 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002965 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002966 &sensor_dev_template_pwm_weight_temp_step,
2967 &sensor_dev_template_pwm_weight_temp_step_tol,
2968 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002969 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002970 &sensor_dev_template_pwm_max, /* 19 */
2971 &sensor_dev_template_pwm_step, /* 20 */
2972 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
2973 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
2974 &sensor_dev_template_pwm_auto_point1_temp,
2975 &sensor_dev_template_pwm_auto_point2_pwm,
2976 &sensor_dev_template_pwm_auto_point2_temp,
2977 &sensor_dev_template_pwm_auto_point3_pwm,
2978 &sensor_dev_template_pwm_auto_point3_temp,
2979 &sensor_dev_template_pwm_auto_point4_pwm,
2980 &sensor_dev_template_pwm_auto_point4_temp,
2981 &sensor_dev_template_pwm_auto_point5_pwm,
2982 &sensor_dev_template_pwm_auto_point5_temp,
2983 &sensor_dev_template_pwm_auto_point6_pwm,
2984 &sensor_dev_template_pwm_auto_point6_temp,
2985 &sensor_dev_template_pwm_auto_point7_pwm,
2986 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002987
Guenter Roeckf73cf632013-03-18 09:22:50 -07002988 NULL
2989};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002990
Guenter Roeckf73cf632013-03-18 09:22:50 -07002991static struct sensor_template_group nct6775_pwm_template_group = {
2992 .templates = nct6775_attributes_pwm_template,
2993 .is_visible = nct6775_pwm_is_visible,
2994 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002995};
2996
2997static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002998show_vid(struct device *dev, struct device_attribute *attr, char *buf)
2999{
3000 struct nct6775_data *data = dev_get_drvdata(dev);
3001 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3002}
3003
3004static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3005
Guenter Roecka6bd5872012-12-04 03:13:34 -08003006/* Case open detection */
3007
3008static ssize_t
3009clear_caseopen(struct device *dev, struct device_attribute *attr,
3010 const char *buf, size_t count)
3011{
3012 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003013 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3014 unsigned long val;
3015 u8 reg;
3016 int ret;
3017
3018 if (kstrtoul(buf, 10, &val) || val != 0)
3019 return -EINVAL;
3020
3021 mutex_lock(&data->update_lock);
3022
3023 /*
3024 * Use CR registers to clear caseopen status.
3025 * The CR registers are the same for all chips, and not all chips
3026 * support clearing the caseopen status through "regular" registers.
3027 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003028 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003029 if (ret) {
3030 count = ret;
3031 goto error;
3032 }
3033
Guenter Roeckdf612d52013-07-08 13:15:04 -07003034 superio_select(data->sioreg, NCT6775_LD_ACPI);
3035 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003036 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003037 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003038 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003039 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3040 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003041
3042 data->valid = false; /* Force cache refresh */
3043error:
3044 mutex_unlock(&data->update_lock);
3045 return count;
3046}
3047
Guenter Roeckf73cf632013-03-18 09:22:50 -07003048static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3049 clear_caseopen, INTRUSION_ALARM_BASE);
3050static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3051 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003052static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3053 store_beep, INTRUSION_ALARM_BASE);
3054static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3055 store_beep, INTRUSION_ALARM_BASE + 1);
3056static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3057 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003058
3059static umode_t nct6775_other_is_visible(struct kobject *kobj,
3060 struct attribute *attr, int index)
3061{
3062 struct device *dev = container_of(kobj, struct device, kobj);
3063 struct nct6775_data *data = dev_get_drvdata(dev);
3064
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003065 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003066 return 0;
3067
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003068 if (index == 1 || index == 2) {
3069 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003070 return 0;
3071 }
3072
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003073 if (index == 3 || index == 4) {
3074 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003075 return 0;
3076 }
3077
Guenter Roeckf73cf632013-03-18 09:22:50 -07003078 return attr->mode;
3079}
3080
3081/*
3082 * nct6775_other_is_visible uses the index into the following array
3083 * to determine if attributes should be created or not.
3084 * Any change in order or content must be matched.
3085 */
3086static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003087 &dev_attr_cpu0_vid.attr, /* 0 */
3088 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3089 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3090 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3091 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3092 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
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 -07003102static inline void nct6775_init_device(struct nct6775_data *data)
3103{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003104 int i;
3105 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003106
3107 /* Start monitoring if needed */
3108 if (data->REG_CONFIG) {
3109 tmp = nct6775_read_value(data, data->REG_CONFIG);
3110 if (!(tmp & 0x01))
3111 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3112 }
3113
Guenter Roeckaa136e52012-12-04 03:26:05 -08003114 /* Enable temperature sensors if needed */
3115 for (i = 0; i < NUM_TEMP; i++) {
3116 if (!(data->have_temp & (1 << i)))
3117 continue;
3118 if (!data->reg_temp_config[i])
3119 continue;
3120 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3121 if (tmp & 0x01)
3122 nct6775_write_value(data, data->reg_temp_config[i],
3123 tmp & 0xfe);
3124 }
3125
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003126 /* Enable VBAT monitoring if needed */
3127 tmp = nct6775_read_value(data, data->REG_VBAT);
3128 if (!(tmp & 0x01))
3129 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003130
3131 diode = nct6775_read_value(data, data->REG_DIODE);
3132
3133 for (i = 0; i < data->temp_fixed_num; i++) {
3134 if (!(data->have_temp_fixed & (1 << i)))
3135 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003136 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3137 data->temp_type[i]
3138 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003139 else /* thermistor */
3140 data->temp_type[i] = 4;
3141 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003142}
3143
Guenter Roeckf73cf632013-03-18 09:22:50 -07003144static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003145nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003146{
David Bartley578ab5f2013-06-24 22:28:28 -07003147 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3148 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003149 int sioreg = data->sioreg;
3150 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003151
3152 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3153 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003154 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003155
3156 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003157 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003158
3159 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003160 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003161 fan4min = false;
3162 fan5pin = false;
3163 fan6pin = false;
3164 pwm4pin = false;
3165 pwm5pin = false;
3166 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003167 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003168 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003169
Guenter Roeckdf612d52013-07-08 13:15:04 -07003170 superio_select(sioreg, NCT6775_LD_HWM);
3171 regval = superio_inb(sioreg, SIO_REG_ENABLE);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003172
3173 if (regval & 0x80)
3174 fan3pin = gpok;
3175 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003176 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003177
3178 if (regval & 0x40)
3179 fan4pin = gpok;
3180 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003181 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003182
3183 if (regval & 0x20)
3184 fan5pin = gpok;
3185 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003186 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003187
3188 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003189 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003190 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003191 pwm4pin = false;
3192 pwm5pin = false;
3193 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003194 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003195 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003196 fan3pin = !(regval & 0x80);
3197 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003198
3199 fan4pin = false;
3200 fan4min = false;
3201 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003202 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003203 pwm4pin = false;
3204 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003205 pwm6pin = false;
3206 } else { /* NCT6779D or NCT6791D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003207 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003208
3209 fan3pin = !(regval & (1 << 5));
3210 fan4pin = !(regval & (1 << 6));
3211 fan5pin = !(regval & (1 << 7));
3212
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003213 pwm3pin = !(regval & (1 << 0));
3214 pwm4pin = !(regval & (1 << 1));
3215 pwm5pin = !(regval & (1 << 2));
3216
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003217 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003218
3219 if (data->kind == nct6791) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003220 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003221 fan6pin = (regval & (1 << 1));
3222 pwm6pin = (regval & (1 << 0));
3223 } else { /* NCT6779D */
3224 fan6pin = false;
3225 pwm6pin = false;
3226 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003227 }
3228
David Bartley578ab5f2013-06-24 22:28:28 -07003229 /* fan 1 and 2 (0x03) are always present */
3230 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3231 (fan5pin << 4) | (fan6pin << 5);
3232 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3233 (fan5pin << 4);
3234 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3235 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003236}
3237
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003238static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3239 int *available, int *mask)
3240{
3241 int i;
3242 u8 src;
3243
3244 for (i = 0; i < data->pwm_num && *available; i++) {
3245 int index;
3246
3247 if (!regp[i])
3248 continue;
3249 src = nct6775_read_value(data, regp[i]);
3250 src &= 0x1f;
3251 if (!src || (*mask & (1 << src)))
3252 continue;
3253 if (src >= data->temp_label_num ||
3254 !strlen(data->temp_label[src]))
3255 continue;
3256
3257 index = __ffs(*available);
3258 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3259 *available &= ~(1 << index);
3260 *mask |= 1 << src;
3261 }
3262}
3263
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003264static int nct6775_probe(struct platform_device *pdev)
3265{
3266 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003267 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003268 struct nct6775_data *data;
3269 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003270 int i, s, err = 0;
3271 int src, mask, available;
3272 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003273 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003274 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003275 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003276 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003277 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003278 struct device *hwmon_dev;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003279
3280 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3281 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3282 DRVNAME))
3283 return -EBUSY;
3284
3285 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3286 GFP_KERNEL);
3287 if (!data)
3288 return -ENOMEM;
3289
3290 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003291 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003292 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003293 mutex_init(&data->update_lock);
3294 data->name = nct6775_device_names[data->kind];
3295 data->bank = 0xff; /* Force initial bank selection */
3296 platform_set_drvdata(pdev, data);
3297
3298 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003299 case nct6106:
3300 data->in_num = 9;
3301 data->pwm_num = 3;
3302 data->auto_pwm_num = 4;
3303 data->temp_fixed_num = 3;
3304 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003305 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003306
3307 data->fan_from_reg = fan_from_reg13;
3308 data->fan_from_reg_min = fan_from_reg13;
3309
3310 data->temp_label = nct6776_temp_label;
3311 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3312
3313 data->REG_VBAT = NCT6106_REG_VBAT;
3314 data->REG_DIODE = NCT6106_REG_DIODE;
3315 data->DIODE_MASK = NCT6106_DIODE_MASK;
3316 data->REG_VIN = NCT6106_REG_IN;
3317 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3318 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3319 data->REG_TARGET = NCT6106_REG_TARGET;
3320 data->REG_FAN = NCT6106_REG_FAN;
3321 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3322 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3323 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3324 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3325 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3326 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3327 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3328 data->REG_PWM[0] = NCT6106_REG_PWM;
3329 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3330 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3331 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3332 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3333 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3334 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3335 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3336 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3337 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3338 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3339 data->REG_CRITICAL_TEMP_TOLERANCE
3340 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3341 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3342 data->CRITICAL_PWM_ENABLE_MASK
3343 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3344 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3345 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3346 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3347 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3348 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3349 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3350 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3351 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3352 data->REG_ALARM = NCT6106_REG_ALARM;
3353 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003354 data->REG_BEEP = NCT6106_REG_BEEP;
3355 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003356
3357 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003358 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003359 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003360 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003361 reg_temp_over = NCT6106_REG_TEMP_OVER;
3362 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3363 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3364 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3365 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003366 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3367 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003368
3369 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003370 case nct6775:
3371 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003372 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003373 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003374 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003375 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003376 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003377 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003378
3379 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003380 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003381
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003382 data->fan_from_reg = fan_from_reg16;
3383 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003384 data->target_temp_mask = 0x7f;
3385 data->tolerance_mask = 0x0f;
3386 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003387
Guenter Roeckaa136e52012-12-04 03:26:05 -08003388 data->temp_label = nct6775_temp_label;
3389 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3390
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003391 data->REG_CONFIG = NCT6775_REG_CONFIG;
3392 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003393 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003394 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003395 data->REG_VIN = NCT6775_REG_IN;
3396 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3397 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003398 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003399 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003400 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003401 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003402 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003403 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003404 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3405 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3406 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003407 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003408 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3409 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3410 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3411 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003412 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003413 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3414 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3415 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003416 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3417 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3418 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3419 data->REG_CRITICAL_TEMP_TOLERANCE
3420 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003421 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3422 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003423 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003424 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3425 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3426 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3427 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003428 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003429 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003430
3431 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003432 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003433 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003434 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003435 reg_temp_over = NCT6775_REG_TEMP_OVER;
3436 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3437 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3438 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3439 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3440
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003441 break;
3442 case nct6776:
3443 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003444 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003445 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003446 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003447 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003448 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003449 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003450
3451 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003452 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003453
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003454 data->fan_from_reg = fan_from_reg13;
3455 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003456 data->target_temp_mask = 0xff;
3457 data->tolerance_mask = 0x07;
3458 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003459
Guenter Roeckaa136e52012-12-04 03:26:05 -08003460 data->temp_label = nct6776_temp_label;
3461 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3462
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003463 data->REG_CONFIG = NCT6775_REG_CONFIG;
3464 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003465 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003466 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003467 data->REG_VIN = NCT6775_REG_IN;
3468 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3469 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003470 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003471 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003472 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003473 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003474 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003475 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003476 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3477 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3478 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3479 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003480 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003481 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3482 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003483 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3484 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003485 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3486 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3487 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003488 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3489 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3490 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3491 data->REG_CRITICAL_TEMP_TOLERANCE
3492 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003493 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3494 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003495 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003496 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3497 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3498 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3499 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003500 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003501 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003502
3503 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003504 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003505 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003506 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003507 reg_temp_over = NCT6775_REG_TEMP_OVER;
3508 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3509 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3510 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3511 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3512
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003513 break;
3514 case nct6779:
3515 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003516 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003517 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003518 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003519 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003520 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003521 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003522
3523 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003524 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003525
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003526 data->fan_from_reg = fan_from_reg13;
3527 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003528 data->target_temp_mask = 0xff;
3529 data->tolerance_mask = 0x07;
3530 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531
Guenter Roeckaa136e52012-12-04 03:26:05 -08003532 data->temp_label = nct6779_temp_label;
3533 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3534
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003535 data->REG_CONFIG = NCT6775_REG_CONFIG;
3536 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003537 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003538 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003539 data->REG_VIN = NCT6779_REG_IN;
3540 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3541 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003542 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003543 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003544 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003545 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003546 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003547 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003548 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3549 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3550 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3551 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003552 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003553 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3554 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003555 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3556 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003557 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3558 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3559 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003560 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3561 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3562 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3563 data->REG_CRITICAL_TEMP_TOLERANCE
3564 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003565 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3566 data->CRITICAL_PWM_ENABLE_MASK
3567 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3568 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003569 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3570 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003571 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003572 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3573 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3574 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3575 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003576 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003577 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003578
3579 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003580 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003581 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003582 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003583 reg_temp_over = NCT6779_REG_TEMP_OVER;
3584 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3585 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3586 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3587 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3588
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003589 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003590 case nct6791:
3591 data->in_num = 15;
3592 data->pwm_num = 6;
3593 data->auto_pwm_num = 4;
3594 data->has_fan_div = false;
3595 data->temp_fixed_num = 6;
3596 data->num_temp_alarms = 2;
3597 data->num_temp_beeps = 2;
3598
3599 data->ALARM_BITS = NCT6791_ALARM_BITS;
3600 data->BEEP_BITS = NCT6779_BEEP_BITS;
3601
3602 data->fan_from_reg = fan_from_reg13;
3603 data->fan_from_reg_min = fan_from_reg13;
3604 data->target_temp_mask = 0xff;
3605 data->tolerance_mask = 0x07;
3606 data->speed_tolerance_limit = 63;
3607
3608 data->temp_label = nct6779_temp_label;
3609 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3610
3611 data->REG_CONFIG = NCT6775_REG_CONFIG;
3612 data->REG_VBAT = NCT6775_REG_VBAT;
3613 data->REG_DIODE = NCT6775_REG_DIODE;
3614 data->DIODE_MASK = NCT6775_DIODE_MASK;
3615 data->REG_VIN = NCT6779_REG_IN;
3616 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3617 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3618 data->REG_TARGET = NCT6775_REG_TARGET;
3619 data->REG_FAN = NCT6779_REG_FAN;
3620 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3621 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3622 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3623 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3624 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3625 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3626 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3627 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3628 data->REG_PWM[0] = NCT6775_REG_PWM;
3629 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3630 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003631 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3632 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003633 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3634 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3635 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3636 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3637 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3638 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3639 data->REG_CRITICAL_TEMP_TOLERANCE
3640 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3641 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3642 data->CRITICAL_PWM_ENABLE_MASK
3643 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3644 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3645 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3646 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3647 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003648 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3649 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3650 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3651 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003652 data->REG_ALARM = NCT6791_REG_ALARM;
3653 data->REG_BEEP = NCT6776_REG_BEEP;
3654
3655 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003656 reg_temp_mon = NCT6779_REG_TEMP_MON;
David Bartley578ab5f2013-06-24 22:28:28 -07003657 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003658 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
David Bartley578ab5f2013-06-24 22:28:28 -07003659 reg_temp_over = NCT6779_REG_TEMP_OVER;
3660 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3661 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3662 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3663 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3664
3665 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003666 default:
3667 return -ENODEV;
3668 }
3669 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003670 data->have_temp = 0;
3671
3672 /*
3673 * On some boards, not all available temperature sources are monitored,
3674 * even though some of the monitoring registers are unused.
3675 * Get list of unused monitoring registers, then detect if any fan
3676 * controls are configured to use unmonitored temperature sources.
3677 * If so, assign the unmonitored temperature sources to available
3678 * monitoring registers.
3679 */
3680 mask = 0;
3681 available = 0;
3682 for (i = 0; i < num_reg_temp; i++) {
3683 if (reg_temp[i] == 0)
3684 continue;
3685
3686 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3687 if (!src || (mask & (1 << src)))
3688 available |= 1 << i;
3689
3690 mask |= 1 << src;
3691 }
3692
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003693 /*
3694 * Now find unmonitored temperature registers and enable monitoring
3695 * if additional monitoring registers are available.
3696 */
3697 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3698 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3699
Guenter Roeckaa136e52012-12-04 03:26:05 -08003700 mask = 0;
3701 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3702 for (i = 0; i < num_reg_temp; i++) {
3703 if (reg_temp[i] == 0)
3704 continue;
3705
3706 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3707 if (!src || (mask & (1 << src)))
3708 continue;
3709
3710 if (src >= data->temp_label_num ||
3711 !strlen(data->temp_label[src])) {
3712 dev_info(dev,
3713 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3714 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3715 continue;
3716 }
3717
3718 mask |= 1 << src;
3719
3720 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3721 if (src <= data->temp_fixed_num) {
3722 data->have_temp |= 1 << (src - 1);
3723 data->have_temp_fixed |= 1 << (src - 1);
3724 data->reg_temp[0][src - 1] = reg_temp[i];
3725 data->reg_temp[1][src - 1] = reg_temp_over[i];
3726 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003727 if (reg_temp_crit_h && reg_temp_crit_h[i])
3728 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3729 else if (reg_temp_crit[src - 1])
3730 data->reg_temp[3][src - 1]
3731 = reg_temp_crit[src - 1];
3732 if (reg_temp_crit_l && reg_temp_crit_l[i])
3733 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003734 data->reg_temp_config[src - 1] = reg_temp_config[i];
3735 data->temp_src[src - 1] = src;
3736 continue;
3737 }
3738
3739 if (s >= NUM_TEMP)
3740 continue;
3741
3742 /* Use dynamic index for other sources */
3743 data->have_temp |= 1 << s;
3744 data->reg_temp[0][s] = reg_temp[i];
3745 data->reg_temp[1][s] = reg_temp_over[i];
3746 data->reg_temp[2][s] = reg_temp_hyst[i];
3747 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003748 if (reg_temp_crit_h && reg_temp_crit_h[i])
3749 data->reg_temp[3][s] = reg_temp_crit_h[i];
3750 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003751 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003752 if (reg_temp_crit_l && reg_temp_crit_l[i])
3753 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003754
3755 data->temp_src[s] = src;
3756 s++;
3757 }
3758
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003759 /*
3760 * Repeat with temperatures used for fan control.
3761 * This set of registers does not support limits.
3762 */
3763 for (i = 0; i < num_reg_temp_mon; i++) {
3764 if (reg_temp_mon[i] == 0)
3765 continue;
3766
3767 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3768 if (!src || (mask & (1 << src)))
3769 continue;
3770
3771 if (src >= data->temp_label_num ||
3772 !strlen(data->temp_label[src])) {
3773 dev_info(dev,
3774 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3775 src, i, data->REG_TEMP_SEL[i],
3776 reg_temp_mon[i]);
3777 continue;
3778 }
3779
3780 mask |= 1 << src;
3781
3782 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3783 if (src <= data->temp_fixed_num) {
3784 if (data->have_temp & (1 << (src - 1)))
3785 continue;
3786 data->have_temp |= 1 << (src - 1);
3787 data->have_temp_fixed |= 1 << (src - 1);
3788 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3789 data->temp_src[src - 1] = src;
3790 continue;
3791 }
3792
3793 if (s >= NUM_TEMP)
3794 continue;
3795
3796 /* Use dynamic index for other sources */
3797 data->have_temp |= 1 << s;
3798 data->reg_temp[0][s] = reg_temp_mon[i];
3799 data->temp_src[s] = src;
3800 s++;
3801 }
3802
Guenter Roeckaa136e52012-12-04 03:26:05 -08003803#ifdef USE_ALTERNATE
3804 /*
3805 * Go through the list of alternate temp registers and enable
3806 * if possible.
3807 * The temperature is already monitored if the respective bit in <mask>
3808 * is set.
3809 */
3810 for (i = 0; i < data->temp_label_num - 1; i++) {
3811 if (!reg_temp_alternate[i])
3812 continue;
3813 if (mask & (1 << (i + 1)))
3814 continue;
3815 if (i < data->temp_fixed_num) {
3816 if (data->have_temp & (1 << i))
3817 continue;
3818 data->have_temp |= 1 << i;
3819 data->have_temp_fixed |= 1 << i;
3820 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07003821 if (i < num_reg_temp) {
3822 data->reg_temp[1][i] = reg_temp_over[i];
3823 data->reg_temp[2][i] = reg_temp_hyst[i];
3824 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003825 data->temp_src[i] = i + 1;
3826 continue;
3827 }
3828
3829 if (s >= NUM_TEMP) /* Abort if no more space */
3830 break;
3831
3832 data->have_temp |= 1 << s;
3833 data->reg_temp[0][s] = reg_temp_alternate[i];
3834 data->temp_src[s] = i + 1;
3835 s++;
3836 }
3837#endif /* USE_ALTERNATE */
3838
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003839 /* Initialize the chip */
3840 nct6775_init_device(data);
3841
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003842 err = superio_enter(sio_data->sioreg);
3843 if (err)
3844 return err;
3845
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003846 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3847 switch (data->kind) {
3848 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003849 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003850 break;
3851 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003852 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003853 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003854 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003855 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003856 case nct6791:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003857 break;
3858 }
3859
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003860 /*
3861 * Read VID value
3862 * We can get the VID input values directly at logical device D 0xe3.
3863 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003864 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003865 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3866 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3867 data->vrm = vid_which_vrm();
3868 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003869
3870 if (fan_debounce) {
3871 u8 tmp;
3872
3873 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3874 tmp = superio_inb(sio_data->sioreg,
3875 NCT6775_REG_CR_FAN_DEBOUNCE);
3876 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003877 case nct6106:
3878 tmp |= 0xe0;
3879 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003880 case nct6775:
3881 tmp |= 0x1e;
3882 break;
3883 case nct6776:
3884 case nct6779:
3885 tmp |= 0x3e;
3886 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003887 case nct6791:
3888 tmp |= 0x7e;
3889 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003890 }
3891 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3892 tmp);
3893 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3894 data->name);
3895 }
3896
Guenter Roeckdf612d52013-07-08 13:15:04 -07003897 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003898
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003899 superio_exit(sio_data->sioreg);
3900
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003901 /* Read fan clock dividers immediately */
3902 nct6775_init_fan_common(dev, data);
3903
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003904 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003905 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3906 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003907 if (IS_ERR(group))
3908 return PTR_ERR(group);
3909
3910 data->groups[data->num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003911
Guenter Roeckf73cf632013-03-18 09:22:50 -07003912 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3913 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003914 if (IS_ERR(group))
3915 return PTR_ERR(group);
3916
3917 data->groups[data->num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003918
Guenter Roeckf73cf632013-03-18 09:22:50 -07003919 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3920 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003921 if (IS_ERR(group))
3922 return PTR_ERR(group);
3923
3924 data->groups[data->num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003925
Guenter Roeckf73cf632013-03-18 09:22:50 -07003926 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3927 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003928 if (IS_ERR(group))
3929 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003930
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003931 data->groups[data->num_attr_groups++] = group;
3932 data->groups[data->num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003933
Guenter Roecka150d952013-07-11 22:55:22 -07003934 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
3935 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07003936 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003937}
3938
Guenter Roeckf5776cc2013-12-25 07:25:59 -08003939static void nct6791_enable_io_mapping(int sioaddr)
3940{
3941 int val;
3942
3943 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
3944 if (val & 0x10) {
3945 pr_info("Enabling hardware monitor logical device mappings.\n");
3946 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
3947 val & ~0x10);
3948 }
3949}
3950
Guenter Roeck84d19d92012-12-04 08:01:39 -08003951#ifdef CONFIG_PM
3952static int nct6775_suspend(struct device *dev)
3953{
3954 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08003955
3956 mutex_lock(&data->update_lock);
3957 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07003958 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08003959 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
3960 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
3961 }
3962 mutex_unlock(&data->update_lock);
3963
3964 return 0;
3965}
3966
3967static int nct6775_resume(struct device *dev)
3968{
3969 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08003970 int i, j, err = 0;
Guenter Roeck84d19d92012-12-04 08:01:39 -08003971
3972 mutex_lock(&data->update_lock);
3973 data->bank = 0xff; /* Force initial bank selection */
3974
Guenter Roeckf5776cc2013-12-25 07:25:59 -08003975 if (data->kind == nct6791) {
3976 err = superio_enter(data->sioreg);
3977 if (err)
3978 goto abort;
3979
3980 nct6791_enable_io_mapping(data->sioreg);
3981 superio_exit(data->sioreg);
3982 }
3983
Guenter Roeck84d19d92012-12-04 08:01:39 -08003984 /* Restore limits */
3985 for (i = 0; i < data->in_num; i++) {
3986 if (!(data->have_in & (1 << i)))
3987 continue;
3988
3989 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
3990 data->in[i][1]);
3991 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
3992 data->in[i][2]);
3993 }
3994
Guenter Roeckc409fd42013-04-09 05:04:00 -07003995 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08003996 if (!(data->has_fan_min & (1 << i)))
3997 continue;
3998
3999 nct6775_write_value(data, data->REG_FAN_MIN[i],
4000 data->fan_min[i]);
4001 }
4002
4003 for (i = 0; i < NUM_TEMP; i++) {
4004 if (!(data->have_temp & (1 << i)))
4005 continue;
4006
Guenter Roeckc409fd42013-04-09 05:04:00 -07004007 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004008 if (data->reg_temp[j][i])
4009 nct6775_write_temp(data, data->reg_temp[j][i],
4010 data->temp[j][i]);
4011 }
4012
4013 /* Restore other settings */
4014 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004015 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004016 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4017 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4018 }
4019
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004020abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004021 /* Force re-reading all values */
4022 data->valid = false;
4023 mutex_unlock(&data->update_lock);
4024
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004025 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004026}
4027
4028static const struct dev_pm_ops nct6775_dev_pm_ops = {
4029 .suspend = nct6775_suspend,
4030 .resume = nct6775_resume,
Harald Judt374d1f92013-07-30 19:50:16 +02004031 .freeze = nct6775_suspend,
4032 .restore = nct6775_resume,
Guenter Roeck84d19d92012-12-04 08:01:39 -08004033};
4034
4035#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops)
4036#else
4037#define NCT6775_DEV_PM_OPS NULL
4038#endif /* CONFIG_PM */
4039
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004040static struct platform_driver nct6775_driver = {
4041 .driver = {
4042 .owner = THIS_MODULE,
4043 .name = DRVNAME,
Guenter Roeck84d19d92012-12-04 08:01:39 -08004044 .pm = NCT6775_DEV_PM_OPS,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004045 },
4046 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004047};
4048
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004049static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004050 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004051 "NCT6775F",
4052 "NCT6776D/F",
4053 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004054 "NCT6791D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004055};
4056
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004057/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004058static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004059{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004060 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004061 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004062 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004063
4064 err = superio_enter(sioaddr);
4065 if (err)
4066 return err;
4067
4068 if (force_id)
4069 val = force_id;
4070 else
4071 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4072 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4073 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004074 case SIO_NCT6106_ID:
4075 sio_data->kind = nct6106;
4076 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004077 case SIO_NCT6775_ID:
4078 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004079 break;
4080 case SIO_NCT6776_ID:
4081 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004082 break;
4083 case SIO_NCT6779_ID:
4084 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004085 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004086 case SIO_NCT6791_ID:
4087 sio_data->kind = nct6791;
4088 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004089 default:
4090 if (val != 0xffff)
4091 pr_debug("unsupported chip ID: 0x%04x\n", val);
4092 superio_exit(sioaddr);
4093 return -ENODEV;
4094 }
4095
4096 /* We have a known chip, find the HWM I/O address */
4097 superio_select(sioaddr, NCT6775_LD_HWM);
4098 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4099 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004100 addr = val & IOREGION_ALIGNMENT;
4101 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004102 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4103 superio_exit(sioaddr);
4104 return -ENODEV;
4105 }
4106
4107 /* Activate logical device if needed */
4108 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4109 if (!(val & 0x01)) {
4110 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4111 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4112 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004113
4114 if (sio_data->kind == nct6791)
4115 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004116
4117 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004118 pr_info("Found %s or compatible chip at %#x:%#x\n",
4119 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004120 sio_data->sioreg = sioaddr;
4121
Guenter Roeck698a7c22013-04-05 07:35:25 -07004122 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004123}
4124
4125/*
4126 * when Super-I/O functions move to a separate file, the Super-I/O
4127 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004128 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004129 * must keep track of the device
4130 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004131static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004132
4133static int __init sensors_nct6775_init(void)
4134{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004135 int i, err;
4136 bool found = false;
4137 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004138 struct resource res;
4139 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004140 int sioaddr[2] = { 0x2e, 0x4e };
4141
4142 err = platform_driver_register(&nct6775_driver);
4143 if (err)
4144 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004145
4146 /*
4147 * initialize sio_data->kind and sio_data->sioreg.
4148 *
4149 * when Super-I/O functions move to a separate file, the Super-I/O
4150 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4151 * nct6775 hardware monitor, and call probe()
4152 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004153 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4154 address = nct6775_find(sioaddr[i], &sio_data);
4155 if (address <= 0)
4156 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004157
Guenter Roeck698a7c22013-04-05 07:35:25 -07004158 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004159
Guenter Roeck698a7c22013-04-05 07:35:25 -07004160 pdev[i] = platform_device_alloc(DRVNAME, address);
4161 if (!pdev[i]) {
4162 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004163 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004164 }
4165
4166 err = platform_device_add_data(pdev[i], &sio_data,
4167 sizeof(struct nct6775_sio_data));
4168 if (err)
4169 goto exit_device_put;
4170
4171 memset(&res, 0, sizeof(res));
4172 res.name = DRVNAME;
4173 res.start = address + IOREGION_OFFSET;
4174 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4175 res.flags = IORESOURCE_IO;
4176
4177 err = acpi_check_resource_conflict(&res);
4178 if (err) {
4179 platform_device_put(pdev[i]);
4180 pdev[i] = NULL;
4181 continue;
4182 }
4183
4184 err = platform_device_add_resources(pdev[i], &res, 1);
4185 if (err)
4186 goto exit_device_put;
4187
4188 /* platform_device_add calls probe() */
4189 err = platform_device_add(pdev[i]);
4190 if (err)
4191 goto exit_device_put;
4192 }
4193 if (!found) {
4194 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004195 goto exit_unregister;
4196 }
4197
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004198 return 0;
4199
4200exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004201 platform_device_put(pdev[i]);
4202exit_device_unregister:
4203 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004204 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004205 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004206 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004207exit_unregister:
4208 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004209 return err;
4210}
4211
4212static void __exit sensors_nct6775_exit(void)
4213{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004214 int i;
4215
4216 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4217 if (pdev[i])
4218 platform_device_unregister(pdev[i]);
4219 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004220 platform_driver_unregister(&nct6775_driver);
4221}
4222
4223MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
4224MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
4225MODULE_LICENSE("GPL");
4226
4227module_init(sensors_nct6775_init);
4228module_exit(sensors_nct6775_exit);