blob: 4fcb481032992f475e8d196dc3a9dbcfa2407b30 [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 Delvare7c81c602014-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 Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070042 *
43 * #temp lists the number of monitored temperature sources (first value) plus
44 * the number of directly connectable temperature sensors (second value).
45 */
46
47#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
48
49#include <linux/module.h>
50#include <linux/init.h>
51#include <linux/slab.h>
52#include <linux/jiffies.h>
53#include <linux/platform_device.h>
54#include <linux/hwmon.h>
55#include <linux/hwmon-sysfs.h>
56#include <linux/hwmon-vid.h>
57#include <linux/err.h>
58#include <linux/mutex.h>
59#include <linux/acpi.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080060#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070061#include <linux/io.h>
62#include "lm75.h"
63
Guenter Roeckaa136e52012-12-04 03:26:05 -080064#define USE_ALTERNATE
65
Guenter Roeck8aefb932014-11-16 09:50:04 -080066enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070067
68/* used to set data->name = nct6775_device_names[data->sio_kind] */
69static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070070 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070071 "nct6775",
72 "nct6776",
73 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070074 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080075 "nct6792",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070076};
77
78static unsigned short force_id;
79module_param(force_id, ushort, 0);
80MODULE_PARM_DESC(force_id, "Override the detected device ID");
81
Guenter Roeck47ece962012-12-04 07:59:32 -080082static unsigned short fan_debounce;
83module_param(fan_debounce, ushort, 0);
84MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
85
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070086#define DRVNAME "nct6775"
87
88/*
89 * Super-I/O constants and functions
90 */
91
Guenter Roecka6bd5872012-12-04 03:13:34 -080092#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070093#define NCT6775_LD_HWM 0x0b
94#define NCT6775_LD_VID 0x0d
95
96#define SIO_REG_LDSEL 0x07 /* Logical device select */
97#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
98#define SIO_REG_ENABLE 0x30 /* Logical device enable */
99#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
100
Guenter Roeck6c009502012-07-01 08:23:15 -0700101#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700102#define SIO_NCT6775_ID 0xb470
103#define SIO_NCT6776_ID 0xc330
104#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700105#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800106#define SIO_NCT6792_ID 0xc910
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700107#define SIO_ID_MASK 0xFFF0
108
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800109enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
110
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700111static inline void
112superio_outb(int ioreg, int reg, int val)
113{
114 outb(reg, ioreg);
115 outb(val, ioreg + 1);
116}
117
118static inline int
119superio_inb(int ioreg, int reg)
120{
121 outb(reg, ioreg);
122 return inb(ioreg + 1);
123}
124
125static inline void
126superio_select(int ioreg, int ld)
127{
128 outb(SIO_REG_LDSEL, ioreg);
129 outb(ld, ioreg + 1);
130}
131
132static inline int
133superio_enter(int ioreg)
134{
135 /*
136 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
137 */
138 if (!request_muxed_region(ioreg, 2, DRVNAME))
139 return -EBUSY;
140
141 outb(0x87, ioreg);
142 outb(0x87, ioreg);
143
144 return 0;
145}
146
147static inline void
148superio_exit(int ioreg)
149{
150 outb(0xaa, ioreg);
151 outb(0x02, ioreg);
152 outb(0x02, ioreg + 1);
153 release_region(ioreg, 2);
154}
155
156/*
157 * ISA constants
158 */
159
160#define IOREGION_ALIGNMENT (~7)
161#define IOREGION_OFFSET 5
162#define IOREGION_LENGTH 2
163#define ADDR_REG_OFFSET 0
164#define DATA_REG_OFFSET 1
165
166#define NCT6775_REG_BANK 0x4E
167#define NCT6775_REG_CONFIG 0x40
168
169/*
170 * Not currently used:
171 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
172 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
173 * REG_MAN_ID is at port 0x4f
174 * REG_CHIP_ID is at port 0x58
175 */
176
Guenter Roeckaa136e52012-12-04 03:26:05 -0800177#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
178#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
179
Guenter Roeck6c009502012-07-01 08:23:15 -0700180#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700181#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700182
David Bartley578ab5f2013-06-24 22:28:28 -0700183#define NUM_FAN 6
184
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700185/* Common and NCT6775 specific data */
186
187/* Voltage min/max registers for nr=7..14 are in bank 5 */
188
189static const u16 NCT6775_REG_IN_MAX[] = {
190 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
191 0x55c, 0x55e, 0x560, 0x562 };
192static const u16 NCT6775_REG_IN_MIN[] = {
193 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
194 0x55d, 0x55f, 0x561, 0x563 };
195static const u16 NCT6775_REG_IN[] = {
196 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
197};
198
199#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800200#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700201#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700202
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800203#define NCT6775_REG_FANDIV1 0x506
204#define NCT6775_REG_FANDIV2 0x507
205
Guenter Roeck47ece962012-12-04 07:59:32 -0800206#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
207
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700208static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
209
Guenter Roeck30846992013-06-24 22:21:59 -0700210/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700211
212static const s8 NCT6775_ALARM_BITS[] = {
213 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
214 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
215 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700216 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700217 -1, -1, -1, /* unused */
218 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
219 12, -1 }; /* intrusion0, intrusion1 */
220
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800221#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800222#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800223#define INTRUSION_ALARM_BASE 30
224
Guenter Roeck30846992013-06-24 22:21:59 -0700225static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
226
227/*
228 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
229 * 30..31 intrusion
230 */
231static const s8 NCT6775_BEEP_BITS[] = {
232 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
233 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
234 21, /* global beep enable */
235 6, 7, 11, 28, -1, /* fan1..fan5 */
236 -1, -1, -1, /* unused */
237 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
238 12, -1 }; /* intrusion0, intrusion1 */
239
240#define BEEP_ENABLE_BASE 15
241
Guenter Roecka6bd5872012-12-04 03:13:34 -0800242static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
243static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
244
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800245/* DC or PWM output fan configuration */
246static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
247static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
248
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800249/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800250
David Bartley578ab5f2013-06-24 22:28:28 -0700251static const u16 NCT6775_REG_TARGET[] = {
252 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
253static const u16 NCT6775_REG_FAN_MODE[] = {
254 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800255static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700256 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800257static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700258 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800259static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700260 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
261static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
262 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800263static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
264static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
265
266static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700267 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
268static const u16 NCT6775_REG_PWM[] = {
269 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
270static const u16 NCT6775_REG_PWM_READ[] = {
271 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800272
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800273static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
274static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800275static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700276static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800277
Guenter Roeckaa136e52012-12-04 03:26:05 -0800278static const u16 NCT6775_REG_TEMP[] = {
279 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
280
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800281static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
282
Guenter Roeckaa136e52012-12-04 03:26:05 -0800283static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
284 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
285static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
286 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
287static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
288 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
289
290static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
291 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
292
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800293static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700294 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800295
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800296static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700297 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800298static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700299 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800300static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700301 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800302static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700303 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800304static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700305 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800306
Guenter Roeckaa136e52012-12-04 03:26:05 -0800307static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
308
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800309static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700310 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800311static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700312 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800313
314#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
315#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
316
317static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
318
319static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700320 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800321static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700322 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800323
Guenter Roeckaa136e52012-12-04 03:26:05 -0800324static const char *const nct6775_temp_label[] = {
325 "",
326 "SYSTIN",
327 "CPUTIN",
328 "AUXTIN",
329 "AMD SB-TSI",
330 "PECI Agent 0",
331 "PECI Agent 1",
332 "PECI Agent 2",
333 "PECI Agent 3",
334 "PECI Agent 4",
335 "PECI Agent 5",
336 "PECI Agent 6",
337 "PECI Agent 7",
338 "PCH_CHIP_CPU_MAX_TEMP",
339 "PCH_CHIP_TEMP",
340 "PCH_CPU_TEMP",
341 "PCH_MCH_TEMP",
342 "PCH_DIM0_TEMP",
343 "PCH_DIM1_TEMP",
344 "PCH_DIM2_TEMP",
345 "PCH_DIM3_TEMP"
346};
347
348static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
349 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
350
351static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
352 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
353 0xa07 };
354
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700355/* NCT6776 specific data */
356
357static const s8 NCT6776_ALARM_BITS[] = {
358 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
359 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
360 -1, /* unused */
361 6, 7, 11, 10, 23, /* fan1..fan5 */
362 -1, -1, -1, /* unused */
363 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
364 12, 9 }; /* intrusion0, intrusion1 */
365
Guenter Roeck30846992013-06-24 22:21:59 -0700366static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
367
368static const s8 NCT6776_BEEP_BITS[] = {
369 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
370 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
371 24, /* global beep enable */
372 25, 26, 27, 28, 29, /* fan1..fan5 */
373 -1, -1, -1, /* unused */
374 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
375 30, 31 }; /* intrusion0, intrusion1 */
376
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800377static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700378 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800379
David Bartley578ab5f2013-06-24 22:28:28 -0700380static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
381static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800382
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800383static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800384static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800385
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800386static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700387 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800388
Guenter Roeckaa136e52012-12-04 03:26:05 -0800389static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
390 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
391
392static const char *const nct6776_temp_label[] = {
393 "",
394 "SYSTIN",
395 "CPUTIN",
396 "AUXTIN",
397 "SMBUSMASTER 0",
398 "SMBUSMASTER 1",
399 "SMBUSMASTER 2",
400 "SMBUSMASTER 3",
401 "SMBUSMASTER 4",
402 "SMBUSMASTER 5",
403 "SMBUSMASTER 6",
404 "SMBUSMASTER 7",
405 "PECI Agent 0",
406 "PECI Agent 1",
407 "PCH_CHIP_CPU_MAX_TEMP",
408 "PCH_CHIP_TEMP",
409 "PCH_CPU_TEMP",
410 "PCH_MCH_TEMP",
411 "PCH_DIM0_TEMP",
412 "PCH_DIM1_TEMP",
413 "PCH_DIM2_TEMP",
414 "PCH_DIM3_TEMP",
415 "BYTE_TEMP"
416};
417
418static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
419 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
420
421static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
422 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
423
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700424/* NCT6779 specific data */
425
426static const u16 NCT6779_REG_IN[] = {
427 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
428 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
429
430static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
431 0x459, 0x45A, 0x45B, 0x568 };
432
433static const s8 NCT6779_ALARM_BITS[] = {
434 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
435 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
436 -1, /* unused */
437 6, 7, 11, 10, 23, /* fan1..fan5 */
438 -1, -1, -1, /* unused */
439 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
440 12, 9 }; /* intrusion0, intrusion1 */
441
Guenter Roeck30846992013-06-24 22:21:59 -0700442static const s8 NCT6779_BEEP_BITS[] = {
443 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
444 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
445 24, /* global beep enable */
446 25, 26, 27, 28, 29, /* fan1..fan5 */
447 -1, -1, -1, /* unused */
448 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
449 30, 31 }; /* intrusion0, intrusion1 */
450
David Bartley578ab5f2013-06-24 22:28:28 -0700451static const u16 NCT6779_REG_FAN[] = {
452 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800453static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700454 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800455
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800456static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700457 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700458#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800459static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700460 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800461
Guenter Roeckaa136e52012-12-04 03:26:05 -0800462static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800463static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800464static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
465 0x18, 0x152 };
466static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
467 0x3a, 0x153 };
468static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
469 0x39, 0x155 };
470
471static const u16 NCT6779_REG_TEMP_OFFSET[] = {
472 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
473
474static const char *const nct6779_temp_label[] = {
475 "",
476 "SYSTIN",
477 "CPUTIN",
478 "AUXTIN0",
479 "AUXTIN1",
480 "AUXTIN2",
481 "AUXTIN3",
482 "",
483 "SMBUSMASTER 0",
484 "SMBUSMASTER 1",
485 "SMBUSMASTER 2",
486 "SMBUSMASTER 3",
487 "SMBUSMASTER 4",
488 "SMBUSMASTER 5",
489 "SMBUSMASTER 6",
490 "SMBUSMASTER 7",
491 "PECI Agent 0",
492 "PECI Agent 1",
493 "PCH_CHIP_CPU_MAX_TEMP",
494 "PCH_CHIP_TEMP",
495 "PCH_CPU_TEMP",
496 "PCH_MCH_TEMP",
497 "PCH_DIM0_TEMP",
498 "PCH_DIM1_TEMP",
499 "PCH_DIM2_TEMP",
500 "PCH_DIM3_TEMP",
501 "BYTE_TEMP"
502};
503
504static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
505 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
506 0, 0, 0, 0, 0, 0, 0, 0,
507 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
508 0x408, 0 };
509
510static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
511 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
512
David Bartley578ab5f2013-06-24 22:28:28 -0700513/* NCT6791 specific data */
514
515#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
516
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800517static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
518static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
519static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
520static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
521static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
522static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
523
David Bartley578ab5f2013-06-24 22:28:28 -0700524static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
525 0x459, 0x45A, 0x45B, 0x568, 0x45D };
526
527static const s8 NCT6791_ALARM_BITS[] = {
528 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
529 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
530 -1, /* unused */
531 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
532 -1, -1, /* unused */
533 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
534 12, 9 }; /* intrusion0, intrusion1 */
535
Guenter Roeck8aefb932014-11-16 09:50:04 -0800536/* NCT6792 specific data */
537
538static const u16 NCT6792_REG_TEMP_MON[] = {
539 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
540static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
541 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700542
Guenter Roeck6c009502012-07-01 08:23:15 -0700543/* NCT6102D/NCT6106D specific data */
544
545#define NCT6106_REG_VBAT 0x318
546#define NCT6106_REG_DIODE 0x319
547#define NCT6106_DIODE_MASK 0x01
548
549static const u16 NCT6106_REG_IN_MAX[] = {
550 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
551static const u16 NCT6106_REG_IN_MIN[] = {
552 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
553static const u16 NCT6106_REG_IN[] = {
554 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
555
556static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800557static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700558static const u16 NCT6106_REG_TEMP_HYST[] = {
559 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
560static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700561 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
562static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
563 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
564static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
565 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700566static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
567static const u16 NCT6106_REG_TEMP_CONFIG[] = {
568 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
569
570static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
571static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
572static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
573static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
574
575static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
576static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
577static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
578static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
579static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
580static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
581static const u16 NCT6106_REG_TEMP_SOURCE[] = {
582 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
583
584static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
585static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
586 0x11b, 0x12b, 0x13b };
587
588static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
589#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
590static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
591
592static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
593static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
594static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
595static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
596static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
597static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
598
599static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
600
601static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
602static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
603static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
604static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
605static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
606static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
607
608static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
609static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
610
611static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
612 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
613
614static const s8 NCT6106_ALARM_BITS[] = {
615 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
616 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
617 -1, /* unused */
618 32, 33, 34, -1, -1, /* fan1..fan5 */
619 -1, -1, -1, /* unused */
620 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
621 48, -1 /* intrusion0, intrusion1 */
622};
623
Guenter Roeck30846992013-06-24 22:21:59 -0700624static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
625 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
626
627static const s8 NCT6106_BEEP_BITS[] = {
628 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
629 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
630 32, /* global beep enable */
631 24, 25, 26, 27, 28, /* fan1..fan5 */
632 -1, -1, -1, /* unused */
633 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
634 34, -1 /* intrusion0, intrusion1 */
635};
636
Guenter Roeck6c009502012-07-01 08:23:15 -0700637static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
638 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
639
640static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
641 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
642
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800643static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
644{
645 if (mode == 0 && pwm == 255)
646 return off;
647 return mode + 1;
648}
649
650static int pwm_enable_to_reg(enum pwm_enable mode)
651{
652 if (mode == off)
653 return 0;
654 return mode - 1;
655}
656
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700657/*
658 * Conversions
659 */
660
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800661/* 1 is DC mode, output in ms */
662static unsigned int step_time_from_reg(u8 reg, u8 mode)
663{
664 return mode ? 400 * reg : 100 * reg;
665}
666
667static u8 step_time_to_reg(unsigned int msec, u8 mode)
668{
669 return clamp_val((mode ? (msec + 200) / 400 :
670 (msec + 50) / 100), 1, 255);
671}
672
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800673static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
674{
675 if (reg == 0 || reg == 255)
676 return 0;
677 return 1350000U / (reg << divreg);
678}
679
680static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
681{
682 if ((reg & 0xff1f) == 0xff1f)
683 return 0;
684
685 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
686
687 if (reg == 0)
688 return 0;
689
690 return 1350000U / reg;
691}
692
693static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
694{
695 if (reg == 0 || reg == 0xffff)
696 return 0;
697
698 /*
699 * Even though the registers are 16 bit wide, the fan divisor
700 * still applies.
701 */
702 return 1350000U / (reg << divreg);
703}
704
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800705static u16 fan_to_reg(u32 fan, unsigned int divreg)
706{
707 if (!fan)
708 return 0;
709
710 return (1350000U / fan) >> divreg;
711}
712
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800713static inline unsigned int
714div_from_reg(u8 reg)
715{
716 return 1 << reg;
717}
718
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700719/*
720 * Some of the voltage inputs have internal scaling, the tables below
721 * contain 8 (the ADC LSB in mV) * scaling factor * 100
722 */
723static const u16 scale_in[15] = {
724 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
725 800, 800
726};
727
728static inline long in_from_reg(u8 reg, u8 nr)
729{
730 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
731}
732
733static inline u8 in_to_reg(u32 val, u8 nr)
734{
735 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
736}
737
738/*
739 * Data structures and manipulation thereof
740 */
741
742struct nct6775_data {
743 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700744 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700745 enum kinds kind;
746 const char *name;
747
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700748 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700749
Guenter Roeckb7a61352013-04-02 22:14:06 -0700750 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
751 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800752 */
753 u8 temp_src[NUM_TEMP];
754 u16 reg_temp_config[NUM_TEMP];
755 const char * const *temp_label;
756 int temp_label_num;
757
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700758 u16 REG_CONFIG;
759 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800760 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700761 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700762
763 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700764 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700765
766 const u16 *REG_VIN;
767 const u16 *REG_IN_MINMAX[2];
768
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800769 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800770 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800771 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800772 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800773 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700774 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800775 const u16 *REG_FAN_TIME[3];
776
777 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800778
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800779 const u8 *REG_PWM_MODE;
780 const u8 *PWM_MODE_MASK;
781
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800782 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
783 * [3]=pwm_max, [4]=pwm_step,
784 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800785 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800786 const u16 *REG_PWM_READ;
787
Guenter Roeck6c009502012-07-01 08:23:15 -0700788 const u16 *REG_CRITICAL_PWM_ENABLE;
789 u8 CRITICAL_PWM_ENABLE_MASK;
790 const u16 *REG_CRITICAL_PWM;
791
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800792 const u16 *REG_AUTO_TEMP;
793 const u16 *REG_AUTO_PWM;
794
795 const u16 *REG_CRITICAL_TEMP;
796 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
797
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800798 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800799 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800800 const u16 *REG_WEIGHT_TEMP_SEL;
801 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
802
Guenter Roeckaa136e52012-12-04 03:26:05 -0800803 const u16 *REG_TEMP_OFFSET;
804
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700805 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700806 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700807
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800808 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
809 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
810
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700811 struct mutex update_lock;
812 bool valid; /* true if following fields are valid */
813 unsigned long last_updated; /* In jiffies */
814
815 /* Register values */
816 u8 bank; /* current register bank */
817 u8 in_num; /* number of in inputs we have */
818 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700819 unsigned int rpm[NUM_FAN];
820 u16 fan_min[NUM_FAN];
821 u8 fan_pulses[NUM_FAN];
822 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800823 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800824 u8 has_fan; /* some fan inputs can be disabled */
825 u8 has_fan_min; /* some fans don't have min register */
826 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700827
Guenter Roeck6c009502012-07-01 08:23:15 -0700828 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700829 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800830 u8 temp_fixed_num; /* 3 or 6 */
831 u8 temp_type[NUM_TEMP_FIXED];
832 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300833 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
834 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700835 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700836 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700837
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800838 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700839 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
840 * 0->PWM variable duty cycle
841 */
842 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800843 /* 0->off
844 * 1->manual
845 * 2->thermal cruise mode (also called SmartFan I)
846 * 3->fan speed cruise mode
847 * 4->SmartFan III
848 * 5->enhanced variable thermal cruise (SmartFan IV)
849 */
David Bartley578ab5f2013-06-24 22:28:28 -0700850 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
851 * [3]=pwm_max, [4]=pwm_step,
852 * [5]=weight_duty_step, [6]=weight_duty_base
853 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800854
David Bartley578ab5f2013-06-24 22:28:28 -0700855 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800856 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700857 u32 target_speed[NUM_FAN];
858 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800859 u8 speed_tolerance_limit;
860
David Bartley578ab5f2013-06-24 22:28:28 -0700861 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800862 u8 tolerance_mask;
863
David Bartley578ab5f2013-06-24 22:28:28 -0700864 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800865
866 /* Automatic fan speed control registers */
867 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700868 u8 auto_pwm[NUM_FAN][7];
869 u8 auto_temp[NUM_FAN][7];
870 u8 pwm_temp_sel[NUM_FAN];
871 u8 pwm_weight_temp_sel[NUM_FAN];
872 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
873 * 2->temp_base
874 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800875
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700876 u8 vid;
877 u8 vrm;
878
Guenter Roeckf73cf632013-03-18 09:22:50 -0700879 bool have_vid;
880
Guenter Roeckaa136e52012-12-04 03:26:05 -0800881 u16 have_temp;
882 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700883 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800884
Guenter Roeck84d19d92012-12-04 08:01:39 -0800885 /* Remember extra register values over suspend/resume */
886 u8 vbat;
887 u8 fandiv1;
888 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800889 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700890};
891
892struct nct6775_sio_data {
893 int sioreg;
894 enum kinds kind;
895};
896
Guenter Roeckf73cf632013-03-18 09:22:50 -0700897struct sensor_device_template {
898 struct device_attribute dev_attr;
899 union {
900 struct {
901 u8 nr;
902 u8 index;
903 } s;
904 int index;
905 } u;
906 bool s2; /* true if both index and nr are used */
907};
908
909struct sensor_device_attr_u {
910 union {
911 struct sensor_device_attribute a1;
912 struct sensor_device_attribute_2 a2;
913 } u;
914 char name[32];
915};
916
917#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
918 .attr = {.name = _template, .mode = _mode }, \
919 .show = _show, \
920 .store = _store, \
921}
922
923#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
924 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
925 .u.index = _index, \
926 .s2 = false }
927
928#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
929 _nr, _index) \
930 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
931 .u.s.index = _index, \
932 .u.s.nr = _nr, \
933 .s2 = true }
934
935#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
936static struct sensor_device_template sensor_dev_template_##_name \
937 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
938 _index)
939
940#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
941 _nr, _index) \
942static struct sensor_device_template sensor_dev_template_##_name \
943 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
944 _nr, _index)
945
946struct sensor_template_group {
947 struct sensor_device_template **templates;
948 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
949 int base;
950};
951
952static struct attribute_group *
953nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
954 int repeat)
955{
956 struct attribute_group *group;
957 struct sensor_device_attr_u *su;
958 struct sensor_device_attribute *a;
959 struct sensor_device_attribute_2 *a2;
960 struct attribute **attrs;
961 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300962 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700963
964 if (repeat <= 0)
965 return ERR_PTR(-EINVAL);
966
967 t = tg->templates;
968 for (count = 0; *t; t++, count++)
969 ;
970
971 if (count == 0)
972 return ERR_PTR(-EINVAL);
973
974 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
975 if (group == NULL)
976 return ERR_PTR(-ENOMEM);
977
978 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
979 GFP_KERNEL);
980 if (attrs == NULL)
981 return ERR_PTR(-ENOMEM);
982
983 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
984 GFP_KERNEL);
985 if (su == NULL)
986 return ERR_PTR(-ENOMEM);
987
988 group->attrs = attrs;
989 group->is_visible = tg->is_visible;
990
991 for (i = 0; i < repeat; i++) {
992 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300993 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -0700994 snprintf(su->name, sizeof(su->name),
995 (*t)->dev_attr.attr.name, tg->base + i);
996 if ((*t)->s2) {
997 a2 = &su->u.a2;
998 a2->dev_attr.attr.name = su->name;
999 a2->nr = (*t)->u.s.nr + i;
1000 a2->index = (*t)->u.s.index;
1001 a2->dev_attr.attr.mode =
1002 (*t)->dev_attr.attr.mode;
1003 a2->dev_attr.show = (*t)->dev_attr.show;
1004 a2->dev_attr.store = (*t)->dev_attr.store;
1005 *attrs = &a2->dev_attr.attr;
1006 } else {
1007 a = &su->u.a1;
1008 a->dev_attr.attr.name = su->name;
1009 a->index = (*t)->u.index + i;
1010 a->dev_attr.attr.mode =
1011 (*t)->dev_attr.attr.mode;
1012 a->dev_attr.show = (*t)->dev_attr.show;
1013 a->dev_attr.store = (*t)->dev_attr.store;
1014 *attrs = &a->dev_attr.attr;
1015 }
1016 attrs++;
1017 su++;
1018 t++;
1019 }
1020 }
1021
Guenter Roeckf73cf632013-03-18 09:22:50 -07001022 return group;
1023}
1024
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001025static bool is_word_sized(struct nct6775_data *data, u16 reg)
1026{
1027 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001028 case nct6106:
1029 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1030 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1031 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001032 case nct6775:
1033 return (((reg & 0xff00) == 0x100 ||
1034 (reg & 0xff00) == 0x200) &&
1035 ((reg & 0x00ff) == 0x50 ||
1036 (reg & 0x00ff) == 0x53 ||
1037 (reg & 0x00ff) == 0x55)) ||
1038 (reg & 0xfff0) == 0x630 ||
1039 reg == 0x640 || reg == 0x642 ||
1040 reg == 0x662 ||
1041 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1042 reg == 0x73 || reg == 0x75 || reg == 0x77;
1043 case nct6776:
1044 return (((reg & 0xff00) == 0x100 ||
1045 (reg & 0xff00) == 0x200) &&
1046 ((reg & 0x00ff) == 0x50 ||
1047 (reg & 0x00ff) == 0x53 ||
1048 (reg & 0x00ff) == 0x55)) ||
1049 (reg & 0xfff0) == 0x630 ||
1050 reg == 0x402 ||
1051 reg == 0x640 || reg == 0x642 ||
1052 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1053 reg == 0x73 || reg == 0x75 || reg == 0x77;
1054 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001055 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001056 case nct6792:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001057 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001058 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001059 reg == 0x402 ||
1060 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1061 reg == 0x640 || reg == 0x642 ||
1062 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001063 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001064 }
1065 return false;
1066}
1067
1068/*
1069 * On older chips, only registers 0x50-0x5f are banked.
1070 * On more recent chips, all registers are banked.
1071 * Assume that is the case and set the bank number for each access.
1072 * Cache the bank number so it only needs to be set if it changes.
1073 */
1074static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1075{
1076 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001077
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001078 if (data->bank != bank) {
1079 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1080 outb_p(bank, data->addr + DATA_REG_OFFSET);
1081 data->bank = bank;
1082 }
1083}
1084
1085static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1086{
1087 int res, word_sized = is_word_sized(data, reg);
1088
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001089 nct6775_set_bank(data, reg);
1090 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1091 res = inb_p(data->addr + DATA_REG_OFFSET);
1092 if (word_sized) {
1093 outb_p((reg & 0xff) + 1,
1094 data->addr + ADDR_REG_OFFSET);
1095 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1096 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001097 return res;
1098}
1099
1100static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1101{
1102 int word_sized = is_word_sized(data, reg);
1103
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001104 nct6775_set_bank(data, reg);
1105 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1106 if (word_sized) {
1107 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1108 outb_p((reg & 0xff) + 1,
1109 data->addr + ADDR_REG_OFFSET);
1110 }
1111 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001112 return 0;
1113}
1114
Guenter Roeckaa136e52012-12-04 03:26:05 -08001115/* We left-align 8-bit temperature values to make the code simpler */
1116static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1117{
1118 u16 res;
1119
1120 res = nct6775_read_value(data, reg);
1121 if (!is_word_sized(data, reg))
1122 res <<= 8;
1123
1124 return res;
1125}
1126
1127static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1128{
1129 if (!is_word_sized(data, reg))
1130 value >>= 8;
1131 return nct6775_write_value(data, reg, value);
1132}
1133
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001134/* This function assumes that the caller holds data->update_lock */
1135static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1136{
1137 u8 reg;
1138
1139 switch (nr) {
1140 case 0:
1141 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1142 | (data->fan_div[0] & 0x7);
1143 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1144 break;
1145 case 1:
1146 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1147 | ((data->fan_div[1] << 4) & 0x70);
1148 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1149 break;
1150 case 2:
1151 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1152 | (data->fan_div[2] & 0x7);
1153 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1154 break;
1155 case 3:
1156 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1157 | ((data->fan_div[3] << 4) & 0x70);
1158 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1159 break;
1160 }
1161}
1162
1163static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1164{
1165 if (data->kind == nct6775)
1166 nct6775_write_fan_div(data, nr);
1167}
1168
1169static void nct6775_update_fan_div(struct nct6775_data *data)
1170{
1171 u8 i;
1172
1173 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1174 data->fan_div[0] = i & 0x7;
1175 data->fan_div[1] = (i & 0x70) >> 4;
1176 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1177 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001178 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001179 data->fan_div[3] = (i & 0x70) >> 4;
1180}
1181
1182static void nct6775_update_fan_div_common(struct nct6775_data *data)
1183{
1184 if (data->kind == nct6775)
1185 nct6775_update_fan_div(data);
1186}
1187
1188static void nct6775_init_fan_div(struct nct6775_data *data)
1189{
1190 int i;
1191
1192 nct6775_update_fan_div_common(data);
1193 /*
1194 * For all fans, start with highest divider value if the divider
1195 * register is not initialized. This ensures that we get a
1196 * reading from the fan count register, even if it is not optimal.
1197 * We'll compute a better divider later on.
1198 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001199 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001200 if (!(data->has_fan & (1 << i)))
1201 continue;
1202 if (data->fan_div[i] == 0) {
1203 data->fan_div[i] = 7;
1204 nct6775_write_fan_div_common(data, i);
1205 }
1206 }
1207}
1208
1209static void nct6775_init_fan_common(struct device *dev,
1210 struct nct6775_data *data)
1211{
1212 int i;
1213 u8 reg;
1214
1215 if (data->has_fan_div)
1216 nct6775_init_fan_div(data);
1217
1218 /*
1219 * If fan_min is not set (0), set it to 0xff to disable it. This
1220 * prevents the unnecessary warning when fanX_min is reported as 0.
1221 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001222 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001223 if (data->has_fan_min & (1 << i)) {
1224 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1225 if (!reg)
1226 nct6775_write_value(data, data->REG_FAN_MIN[i],
1227 data->has_fan_div ? 0xff
1228 : 0xff1f);
1229 }
1230 }
1231}
1232
1233static void nct6775_select_fan_div(struct device *dev,
1234 struct nct6775_data *data, int nr, u16 reg)
1235{
1236 u8 fan_div = data->fan_div[nr];
1237 u16 fan_min;
1238
1239 if (!data->has_fan_div)
1240 return;
1241
1242 /*
1243 * If we failed to measure the fan speed, or the reported value is not
1244 * in the optimal range, and the clock divider can be modified,
1245 * let's try that for next time.
1246 */
1247 if (reg == 0x00 && fan_div < 0x07)
1248 fan_div++;
1249 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1250 fan_div--;
1251
1252 if (fan_div != data->fan_div[nr]) {
1253 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1254 nr + 1, div_from_reg(data->fan_div[nr]),
1255 div_from_reg(fan_div));
1256
1257 /* Preserve min limit if possible */
1258 if (data->has_fan_min & (1 << nr)) {
1259 fan_min = data->fan_min[nr];
1260 if (fan_div > data->fan_div[nr]) {
1261 if (fan_min != 255 && fan_min > 1)
1262 fan_min >>= 1;
1263 } else {
1264 if (fan_min != 255) {
1265 fan_min <<= 1;
1266 if (fan_min > 254)
1267 fan_min = 254;
1268 }
1269 }
1270 if (fan_min != data->fan_min[nr]) {
1271 data->fan_min[nr] = fan_min;
1272 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1273 fan_min);
1274 }
1275 }
1276 data->fan_div[nr] = fan_div;
1277 nct6775_write_fan_div_common(data, nr);
1278 }
1279}
1280
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001281static void nct6775_update_pwm(struct device *dev)
1282{
1283 struct nct6775_data *data = dev_get_drvdata(dev);
1284 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001285 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001286 bool duty_is_dc;
1287
1288 for (i = 0; i < data->pwm_num; i++) {
1289 if (!(data->has_pwm & (1 << i)))
1290 continue;
1291
1292 duty_is_dc = data->REG_PWM_MODE[i] &&
1293 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1294 & data->PWM_MODE_MASK[i]);
1295 data->pwm_mode[i] = duty_is_dc;
1296
1297 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1298 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1299 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1300 data->pwm[j][i]
1301 = nct6775_read_value(data,
1302 data->REG_PWM[j][i]);
1303 }
1304 }
1305
1306 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1307 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001308
1309 if (!data->temp_tolerance[0][i] ||
1310 data->pwm_enable[i] != speed_cruise)
1311 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1312 if (!data->target_speed_tolerance[i] ||
1313 data->pwm_enable[i] == speed_cruise) {
1314 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001315
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001316 if (data->REG_TOLERANCE_H) {
1317 t |= (nct6775_read_value(data,
1318 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1319 }
1320 data->target_speed_tolerance[i] = t;
1321 }
1322
1323 data->temp_tolerance[1][i] =
1324 nct6775_read_value(data,
1325 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1326
1327 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1328 data->pwm_temp_sel[i] = reg & 0x1f;
1329 /* If fan can stop, report floor as 0 */
1330 if (reg & 0x80)
1331 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001332
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001333 if (!data->REG_WEIGHT_TEMP_SEL[i])
1334 continue;
1335
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001336 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1337 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1338 /* If weight is disabled, report weight source as 0 */
1339 if (j == 1 && !(reg & 0x80))
1340 data->pwm_weight_temp_sel[i] = 0;
1341
1342 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001343 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001344 data->weight_temp[j][i]
1345 = nct6775_read_value(data,
1346 data->REG_WEIGHT_TEMP[j][i]);
1347 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001348 }
1349}
1350
1351static void nct6775_update_pwm_limits(struct device *dev)
1352{
1353 struct nct6775_data *data = dev_get_drvdata(dev);
1354 int i, j;
1355 u8 reg;
1356 u16 reg_t;
1357
1358 for (i = 0; i < data->pwm_num; i++) {
1359 if (!(data->has_pwm & (1 << i)))
1360 continue;
1361
Guenter Roeckc409fd42013-04-09 05:04:00 -07001362 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001363 data->fan_time[j][i] =
1364 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1365 }
1366
1367 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1368 /* Update only in matching mode or if never updated */
1369 if (!data->target_temp[i] ||
1370 data->pwm_enable[i] == thermal_cruise)
1371 data->target_temp[i] = reg_t & data->target_temp_mask;
1372 if (!data->target_speed[i] ||
1373 data->pwm_enable[i] == speed_cruise) {
1374 if (data->REG_TOLERANCE_H) {
1375 reg_t |= (nct6775_read_value(data,
1376 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1377 }
1378 data->target_speed[i] = reg_t;
1379 }
1380
1381 for (j = 0; j < data->auto_pwm_num; j++) {
1382 data->auto_pwm[i][j] =
1383 nct6775_read_value(data,
1384 NCT6775_AUTO_PWM(data, i, j));
1385 data->auto_temp[i][j] =
1386 nct6775_read_value(data,
1387 NCT6775_AUTO_TEMP(data, i, j));
1388 }
1389
1390 /* critical auto_pwm temperature data */
1391 data->auto_temp[i][data->auto_pwm_num] =
1392 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1393
1394 switch (data->kind) {
1395 case nct6775:
1396 reg = nct6775_read_value(data,
1397 NCT6775_REG_CRITICAL_ENAB[i]);
1398 data->auto_pwm[i][data->auto_pwm_num] =
1399 (reg & 0x02) ? 0xff : 0x00;
1400 break;
1401 case nct6776:
1402 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1403 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001404 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001405 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001406 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001407 case nct6792:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001408 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001409 data->REG_CRITICAL_PWM_ENABLE[i]);
1410 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1411 reg = nct6775_read_value(data,
1412 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001413 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001414 reg = 0xff;
1415 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001416 break;
1417 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001418 }
1419}
1420
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001421static struct nct6775_data *nct6775_update_device(struct device *dev)
1422{
1423 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001424 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001425
1426 mutex_lock(&data->update_lock);
1427
Guenter Roeck6445e662013-04-21 09:13:28 -07001428 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001429 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001430 /* Fan clock dividers */
1431 nct6775_update_fan_div_common(data);
1432
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001433 /* Measured voltages and limits */
1434 for (i = 0; i < data->in_num; i++) {
1435 if (!(data->have_in & (1 << i)))
1436 continue;
1437
1438 data->in[i][0] = nct6775_read_value(data,
1439 data->REG_VIN[i]);
1440 data->in[i][1] = nct6775_read_value(data,
1441 data->REG_IN_MINMAX[0][i]);
1442 data->in[i][2] = nct6775_read_value(data,
1443 data->REG_IN_MINMAX[1][i]);
1444 }
1445
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001446 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001447 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001448 u16 reg;
1449
1450 if (!(data->has_fan & (1 << i)))
1451 continue;
1452
1453 reg = nct6775_read_value(data, data->REG_FAN[i]);
1454 data->rpm[i] = data->fan_from_reg(reg,
1455 data->fan_div[i]);
1456
1457 if (data->has_fan_min & (1 << i))
1458 data->fan_min[i] = nct6775_read_value(data,
1459 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001460 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001461 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1462 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001463
1464 nct6775_select_fan_div(dev, data, i, reg);
1465 }
1466
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001467 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001468 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001469
Guenter Roeckaa136e52012-12-04 03:26:05 -08001470 /* Measured temperatures and limits */
1471 for (i = 0; i < NUM_TEMP; i++) {
1472 if (!(data->have_temp & (1 << i)))
1473 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001474 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001475 if (data->reg_temp[j][i])
1476 data->temp[j][i]
1477 = nct6775_read_temp(data,
1478 data->reg_temp[j][i]);
1479 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001480 if (i >= NUM_TEMP_FIXED ||
1481 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001482 continue;
1483 data->temp_offset[i]
1484 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1485 }
1486
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001487 data->alarms = 0;
1488 for (i = 0; i < NUM_REG_ALARM; i++) {
1489 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001490
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001491 if (!data->REG_ALARM[i])
1492 continue;
1493 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1494 data->alarms |= ((u64)alarm) << (i << 3);
1495 }
1496
Guenter Roeck30846992013-06-24 22:21:59 -07001497 data->beeps = 0;
1498 for (i = 0; i < NUM_REG_BEEP; i++) {
1499 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001500
Guenter Roeck30846992013-06-24 22:21:59 -07001501 if (!data->REG_BEEP[i])
1502 continue;
1503 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1504 data->beeps |= ((u64)beep) << (i << 3);
1505 }
1506
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001507 data->last_updated = jiffies;
1508 data->valid = true;
1509 }
1510
1511 mutex_unlock(&data->update_lock);
1512 return data;
1513}
1514
1515/*
1516 * Sysfs callback functions
1517 */
1518static ssize_t
1519show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1520{
1521 struct nct6775_data *data = nct6775_update_device(dev);
1522 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001523 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001524 int nr = sattr->nr;
1525
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001526 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1527}
1528
1529static ssize_t
1530store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1531 size_t count)
1532{
1533 struct nct6775_data *data = dev_get_drvdata(dev);
1534 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001535 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001536 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001537 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001538 int err;
1539
1540 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001541 if (err < 0)
1542 return err;
1543 mutex_lock(&data->update_lock);
1544 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001545 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001546 data->in[nr][index]);
1547 mutex_unlock(&data->update_lock);
1548 return count;
1549}
1550
1551static ssize_t
1552show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1553{
1554 struct nct6775_data *data = nct6775_update_device(dev);
1555 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1556 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001557
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001558 return sprintf(buf, "%u\n",
1559 (unsigned int)((data->alarms >> nr) & 0x01));
1560}
1561
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001562static int find_temp_source(struct nct6775_data *data, int index, int count)
1563{
1564 int source = data->temp_src[index];
1565 int nr;
1566
1567 for (nr = 0; nr < count; nr++) {
1568 int src;
1569
1570 src = nct6775_read_value(data,
1571 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1572 if (src == source)
1573 return nr;
1574 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001575 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001576}
1577
1578static ssize_t
1579show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1580{
1581 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1582 struct nct6775_data *data = nct6775_update_device(dev);
1583 unsigned int alarm = 0;
1584 int nr;
1585
1586 /*
1587 * For temperatures, there is no fixed mapping from registers to alarm
1588 * bits. Alarm bits are determined by the temperature source mapping.
1589 */
1590 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1591 if (nr >= 0) {
1592 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001593
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001594 alarm = (data->alarms >> bit) & 0x01;
1595 }
1596 return sprintf(buf, "%u\n", alarm);
1597}
1598
Guenter Roeck30846992013-06-24 22:21:59 -07001599static ssize_t
1600show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1601{
1602 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1603 struct nct6775_data *data = nct6775_update_device(dev);
1604 int nr = data->BEEP_BITS[sattr->index];
1605
1606 return sprintf(buf, "%u\n",
1607 (unsigned int)((data->beeps >> nr) & 0x01));
1608}
1609
1610static ssize_t
1611store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1612 size_t count)
1613{
1614 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1615 struct nct6775_data *data = dev_get_drvdata(dev);
1616 int nr = data->BEEP_BITS[sattr->index];
1617 int regindex = nr >> 3;
1618 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001619 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001620
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001621 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001622 if (err < 0)
1623 return err;
1624 if (val > 1)
1625 return -EINVAL;
1626
1627 mutex_lock(&data->update_lock);
1628 if (val)
1629 data->beeps |= (1ULL << nr);
1630 else
1631 data->beeps &= ~(1ULL << nr);
1632 nct6775_write_value(data, data->REG_BEEP[regindex],
1633 (data->beeps >> (regindex << 3)) & 0xff);
1634 mutex_unlock(&data->update_lock);
1635 return count;
1636}
1637
1638static ssize_t
1639show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1640{
1641 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1642 struct nct6775_data *data = nct6775_update_device(dev);
1643 unsigned int beep = 0;
1644 int nr;
1645
1646 /*
1647 * For temperatures, there is no fixed mapping from registers to beep
1648 * enable bits. Beep enable bits are determined by the temperature
1649 * source mapping.
1650 */
1651 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1652 if (nr >= 0) {
1653 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001654
Guenter Roeck30846992013-06-24 22:21:59 -07001655 beep = (data->beeps >> bit) & 0x01;
1656 }
1657 return sprintf(buf, "%u\n", beep);
1658}
1659
1660static ssize_t
1661store_temp_beep(struct device *dev, struct device_attribute *attr,
1662 const char *buf, size_t count)
1663{
1664 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1665 struct nct6775_data *data = dev_get_drvdata(dev);
1666 int nr, bit, regindex;
1667 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001668 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001669
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001670 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001671 if (err < 0)
1672 return err;
1673 if (val > 1)
1674 return -EINVAL;
1675
1676 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1677 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001678 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001679
1680 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1681 regindex = bit >> 3;
1682
1683 mutex_lock(&data->update_lock);
1684 if (val)
1685 data->beeps |= (1ULL << bit);
1686 else
1687 data->beeps &= ~(1ULL << bit);
1688 nct6775_write_value(data, data->REG_BEEP[regindex],
1689 (data->beeps >> (regindex << 3)) & 0xff);
1690 mutex_unlock(&data->update_lock);
1691
1692 return count;
1693}
1694
Guenter Roeckf73cf632013-03-18 09:22:50 -07001695static umode_t nct6775_in_is_visible(struct kobject *kobj,
1696 struct attribute *attr, int index)
1697{
1698 struct device *dev = container_of(kobj, struct device, kobj);
1699 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001700 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001701
Guenter Roeckf73cf632013-03-18 09:22:50 -07001702 if (!(data->have_in & (1 << in)))
1703 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001704
Guenter Roeckf73cf632013-03-18 09:22:50 -07001705 return attr->mode;
1706}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001707
Guenter Roeckf73cf632013-03-18 09:22:50 -07001708SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1709SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001710SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1711 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001712SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1713 store_in_reg, 0, 1);
1714SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1715 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001716
Guenter Roeckf73cf632013-03-18 09:22:50 -07001717/*
1718 * nct6775_in_is_visible uses the index into the following array
1719 * to determine if attributes should be created or not.
1720 * Any change in order or content must be matched.
1721 */
1722static struct sensor_device_template *nct6775_attributes_in_template[] = {
1723 &sensor_dev_template_in_input,
1724 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001725 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001726 &sensor_dev_template_in_min,
1727 &sensor_dev_template_in_max,
1728 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001729};
1730
Guenter Roeckf73cf632013-03-18 09:22:50 -07001731static struct sensor_template_group nct6775_in_template_group = {
1732 .templates = nct6775_attributes_in_template,
1733 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001734};
1735
1736static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001737show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1738{
1739 struct nct6775_data *data = nct6775_update_device(dev);
1740 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1741 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001742
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001743 return sprintf(buf, "%d\n", data->rpm[nr]);
1744}
1745
1746static ssize_t
1747show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1748{
1749 struct nct6775_data *data = nct6775_update_device(dev);
1750 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1751 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001752
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001753 return sprintf(buf, "%d\n",
1754 data->fan_from_reg_min(data->fan_min[nr],
1755 data->fan_div[nr]));
1756}
1757
1758static ssize_t
1759show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1760{
1761 struct nct6775_data *data = nct6775_update_device(dev);
1762 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1763 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001764
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001765 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1766}
1767
1768static ssize_t
1769store_fan_min(struct device *dev, struct device_attribute *attr,
1770 const char *buf, size_t count)
1771{
1772 struct nct6775_data *data = dev_get_drvdata(dev);
1773 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1774 int nr = sattr->index;
1775 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001776 unsigned int reg;
1777 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001778 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001779
1780 err = kstrtoul(buf, 10, &val);
1781 if (err < 0)
1782 return err;
1783
1784 mutex_lock(&data->update_lock);
1785 if (!data->has_fan_div) {
1786 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1787 if (!val) {
1788 val = 0xff1f;
1789 } else {
1790 if (val > 1350000U)
1791 val = 135000U;
1792 val = 1350000U / val;
1793 val = (val & 0x1f) | ((val << 3) & 0xff00);
1794 }
1795 data->fan_min[nr] = val;
1796 goto write_min; /* Leave fan divider alone */
1797 }
1798 if (!val) {
1799 /* No min limit, alarm disabled */
1800 data->fan_min[nr] = 255;
1801 new_div = data->fan_div[nr]; /* No change */
1802 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1803 goto write_div;
1804 }
1805 reg = 1350000U / val;
1806 if (reg >= 128 * 255) {
1807 /*
1808 * Speed below this value cannot possibly be represented,
1809 * even with the highest divider (128)
1810 */
1811 data->fan_min[nr] = 254;
1812 new_div = 7; /* 128 == (1 << 7) */
1813 dev_warn(dev,
1814 "fan%u low limit %lu below minimum %u, set to minimum\n",
1815 nr + 1, val, data->fan_from_reg_min(254, 7));
1816 } else if (!reg) {
1817 /*
1818 * Speed above this value cannot possibly be represented,
1819 * even with the lowest divider (1)
1820 */
1821 data->fan_min[nr] = 1;
1822 new_div = 0; /* 1 == (1 << 0) */
1823 dev_warn(dev,
1824 "fan%u low limit %lu above maximum %u, set to maximum\n",
1825 nr + 1, val, data->fan_from_reg_min(1, 0));
1826 } else {
1827 /*
1828 * Automatically pick the best divider, i.e. the one such
1829 * that the min limit will correspond to a register value
1830 * in the 96..192 range
1831 */
1832 new_div = 0;
1833 while (reg > 192 && new_div < 7) {
1834 reg >>= 1;
1835 new_div++;
1836 }
1837 data->fan_min[nr] = reg;
1838 }
1839
1840write_div:
1841 /*
1842 * Write both the fan clock divider (if it changed) and the new
1843 * fan min (unconditionally)
1844 */
1845 if (new_div != data->fan_div[nr]) {
1846 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1847 nr + 1, div_from_reg(data->fan_div[nr]),
1848 div_from_reg(new_div));
1849 data->fan_div[nr] = new_div;
1850 nct6775_write_fan_div_common(data, nr);
1851 /* Give the chip time to sample a new speed value */
1852 data->last_updated = jiffies;
1853 }
1854
1855write_min:
1856 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1857 mutex_unlock(&data->update_lock);
1858
1859 return count;
1860}
1861
Guenter Roeck5c25d952012-12-11 07:29:06 -08001862static ssize_t
1863show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1864{
1865 struct nct6775_data *data = nct6775_update_device(dev);
1866 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1867 int p = data->fan_pulses[sattr->index];
1868
1869 return sprintf(buf, "%d\n", p ? : 4);
1870}
1871
1872static ssize_t
1873store_fan_pulses(struct device *dev, struct device_attribute *attr,
1874 const char *buf, size_t count)
1875{
1876 struct nct6775_data *data = dev_get_drvdata(dev);
1877 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1878 int nr = sattr->index;
1879 unsigned long val;
1880 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001881 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001882
1883 err = kstrtoul(buf, 10, &val);
1884 if (err < 0)
1885 return err;
1886
1887 if (val > 4)
1888 return -EINVAL;
1889
1890 mutex_lock(&data->update_lock);
1891 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001892 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1893 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1894 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1895 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001896 mutex_unlock(&data->update_lock);
1897
1898 return count;
1899}
1900
Guenter Roeckf73cf632013-03-18 09:22:50 -07001901static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1902 struct attribute *attr, int index)
1903{
1904 struct device *dev = container_of(kobj, struct device, kobj);
1905 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001906 int fan = index / 6; /* fan index */
1907 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001908
1909 if (!(data->has_fan & (1 << fan)))
1910 return 0;
1911
1912 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1913 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001914 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001915 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001916 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1917 return 0;
1918 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001919 return 0;
1920
1921 return attr->mode;
1922}
1923
1924SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1925SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1926 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001927SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1928 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001929SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1930 store_fan_pulses, 0);
1931SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1932 store_fan_min, 0);
1933SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1934
1935/*
1936 * nct6775_fan_is_visible uses the index into the following array
1937 * to determine if attributes should be created or not.
1938 * Any change in order or content must be matched.
1939 */
1940static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1941 &sensor_dev_template_fan_input,
1942 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001943 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001944 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001945 &sensor_dev_template_fan_min, /* 4 */
1946 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001947 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001948};
1949
Guenter Roeckf73cf632013-03-18 09:22:50 -07001950static struct sensor_template_group nct6775_fan_template_group = {
1951 .templates = nct6775_attributes_fan_template,
1952 .is_visible = nct6775_fan_is_visible,
1953 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001954};
1955
1956static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001957show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1958{
1959 struct nct6775_data *data = nct6775_update_device(dev);
1960 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1961 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001962
Guenter Roeckaa136e52012-12-04 03:26:05 -08001963 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1964}
1965
1966static ssize_t
1967show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1968{
1969 struct nct6775_data *data = nct6775_update_device(dev);
1970 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1971 int nr = sattr->nr;
1972 int index = sattr->index;
1973
1974 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1975}
1976
1977static ssize_t
1978store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1979 size_t count)
1980{
1981 struct nct6775_data *data = dev_get_drvdata(dev);
1982 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1983 int nr = sattr->nr;
1984 int index = sattr->index;
1985 int err;
1986 long val;
1987
1988 err = kstrtol(buf, 10, &val);
1989 if (err < 0)
1990 return err;
1991
1992 mutex_lock(&data->update_lock);
1993 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
1994 nct6775_write_temp(data, data->reg_temp[index][nr],
1995 data->temp[index][nr]);
1996 mutex_unlock(&data->update_lock);
1997 return count;
1998}
1999
2000static ssize_t
2001show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2002{
2003 struct nct6775_data *data = nct6775_update_device(dev);
2004 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2005
2006 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2007}
2008
2009static ssize_t
2010store_temp_offset(struct device *dev, struct device_attribute *attr,
2011 const char *buf, size_t count)
2012{
2013 struct nct6775_data *data = dev_get_drvdata(dev);
2014 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2015 int nr = sattr->index;
2016 long val;
2017 int err;
2018
2019 err = kstrtol(buf, 10, &val);
2020 if (err < 0)
2021 return err;
2022
2023 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2024
2025 mutex_lock(&data->update_lock);
2026 data->temp_offset[nr] = val;
2027 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2028 mutex_unlock(&data->update_lock);
2029
2030 return count;
2031}
2032
2033static ssize_t
2034show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2035{
2036 struct nct6775_data *data = nct6775_update_device(dev);
2037 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2038 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002039
Guenter Roeckaa136e52012-12-04 03:26:05 -08002040 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2041}
2042
2043static ssize_t
2044store_temp_type(struct device *dev, struct device_attribute *attr,
2045 const char *buf, size_t count)
2046{
2047 struct nct6775_data *data = nct6775_update_device(dev);
2048 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2049 int nr = sattr->index;
2050 unsigned long val;
2051 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002052 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002053
2054 err = kstrtoul(buf, 10, &val);
2055 if (err < 0)
2056 return err;
2057
2058 if (val != 1 && val != 3 && val != 4)
2059 return -EINVAL;
2060
2061 mutex_lock(&data->update_lock);
2062
2063 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002064 vbit = 0x02 << nr;
2065 dbit = data->DIODE_MASK << nr;
2066 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2067 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002068 switch (val) {
2069 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002070 vbat |= vbit;
2071 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002072 break;
2073 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002074 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002075 break;
2076 case 4: /* thermistor */
2077 break;
2078 }
2079 nct6775_write_value(data, data->REG_VBAT, vbat);
2080 nct6775_write_value(data, data->REG_DIODE, diode);
2081
2082 mutex_unlock(&data->update_lock);
2083 return count;
2084}
2085
Guenter Roeckf73cf632013-03-18 09:22:50 -07002086static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2087 struct attribute *attr, int index)
2088{
2089 struct device *dev = container_of(kobj, struct device, kobj);
2090 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002091 int temp = index / 10; /* temp index */
2092 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002093
2094 if (!(data->have_temp & (1 << temp)))
2095 return 0;
2096
2097 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2098 return 0; /* alarm */
2099
Guenter Roeck30846992013-06-24 22:21:59 -07002100 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2101 return 0; /* beep */
2102
2103 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002104 return 0;
2105
Guenter Roeck30846992013-06-24 22:21:59 -07002106 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002107 return 0;
2108
Guenter Roeck30846992013-06-24 22:21:59 -07002109 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002110 return 0;
2111
Guenter Roeck30846992013-06-24 22:21:59 -07002112 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002113 return 0;
2114
2115 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002116 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002117 return 0;
2118
2119 return attr->mode;
2120}
2121
2122SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2123SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2124SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2125 store_temp, 0, 1);
2126SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2127 show_temp, store_temp, 0, 2);
2128SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2129 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002130SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2131 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002132SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2133 show_temp_offset, store_temp_offset, 0);
2134SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2135 store_temp_type, 0);
2136SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002137SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2138 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002139
2140/*
2141 * nct6775_temp_is_visible uses the index into the following array
2142 * to determine if attributes should be created or not.
2143 * Any change in order or content must be matched.
2144 */
2145static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2146 &sensor_dev_template_temp_input,
2147 &sensor_dev_template_temp_label,
2148 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002149 &sensor_dev_template_temp_beep, /* 3 */
2150 &sensor_dev_template_temp_max, /* 4 */
2151 &sensor_dev_template_temp_max_hyst, /* 5 */
2152 &sensor_dev_template_temp_crit, /* 6 */
2153 &sensor_dev_template_temp_lcrit, /* 7 */
2154 &sensor_dev_template_temp_offset, /* 8 */
2155 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002156 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002157};
2158
Guenter Roeckf73cf632013-03-18 09:22:50 -07002159static struct sensor_template_group nct6775_temp_template_group = {
2160 .templates = nct6775_attributes_temp_template,
2161 .is_visible = nct6775_temp_is_visible,
2162 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002163};
2164
Guenter Roeckaa136e52012-12-04 03:26:05 -08002165static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002166show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2167{
2168 struct nct6775_data *data = nct6775_update_device(dev);
2169 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2170
2171 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2172}
2173
2174static ssize_t
2175store_pwm_mode(struct device *dev, struct device_attribute *attr,
2176 const char *buf, size_t count)
2177{
2178 struct nct6775_data *data = dev_get_drvdata(dev);
2179 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2180 int nr = sattr->index;
2181 unsigned long val;
2182 int err;
2183 u8 reg;
2184
2185 err = kstrtoul(buf, 10, &val);
2186 if (err < 0)
2187 return err;
2188
2189 if (val > 1)
2190 return -EINVAL;
2191
2192 /* Setting DC mode is not supported for all chips/channels */
2193 if (data->REG_PWM_MODE[nr] == 0) {
2194 if (val)
2195 return -EINVAL;
2196 return count;
2197 }
2198
2199 mutex_lock(&data->update_lock);
2200 data->pwm_mode[nr] = val;
2201 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2202 reg &= ~data->PWM_MODE_MASK[nr];
2203 if (val)
2204 reg |= data->PWM_MODE_MASK[nr];
2205 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2206 mutex_unlock(&data->update_lock);
2207 return count;
2208}
2209
2210static ssize_t
2211show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2212{
2213 struct nct6775_data *data = nct6775_update_device(dev);
2214 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2215 int nr = sattr->nr;
2216 int index = sattr->index;
2217 int pwm;
2218
2219 /*
2220 * For automatic fan control modes, show current pwm readings.
2221 * Otherwise, show the configured value.
2222 */
2223 if (index == 0 && data->pwm_enable[nr] > manual)
2224 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2225 else
2226 pwm = data->pwm[index][nr];
2227
2228 return sprintf(buf, "%d\n", pwm);
2229}
2230
2231static ssize_t
2232store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2233 size_t count)
2234{
2235 struct nct6775_data *data = dev_get_drvdata(dev);
2236 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2237 int nr = sattr->nr;
2238 int index = sattr->index;
2239 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002240 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2241 int maxval[7]
2242 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002243 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002244 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002245
2246 err = kstrtoul(buf, 10, &val);
2247 if (err < 0)
2248 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002249 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002250
2251 mutex_lock(&data->update_lock);
2252 data->pwm[index][nr] = val;
2253 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002254 if (index == 2) { /* floor: disable if val == 0 */
2255 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2256 reg &= 0x7f;
2257 if (val)
2258 reg |= 0x80;
2259 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2260 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002261 mutex_unlock(&data->update_lock);
2262 return count;
2263}
2264
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002265/* Returns 0 if OK, -EINVAL otherwise */
2266static int check_trip_points(struct nct6775_data *data, int nr)
2267{
2268 int i;
2269
2270 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2271 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2272 return -EINVAL;
2273 }
2274 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2275 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2276 return -EINVAL;
2277 }
2278 /* validate critical temperature and pwm if enabled (pwm > 0) */
2279 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2280 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2281 data->auto_temp[nr][data->auto_pwm_num] ||
2282 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2283 data->auto_pwm[nr][data->auto_pwm_num])
2284 return -EINVAL;
2285 }
2286 return 0;
2287}
2288
2289static void pwm_update_registers(struct nct6775_data *data, int nr)
2290{
2291 u8 reg;
2292
2293 switch (data->pwm_enable[nr]) {
2294 case off:
2295 case manual:
2296 break;
2297 case speed_cruise:
2298 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2299 reg = (reg & ~data->tolerance_mask) |
2300 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2301 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2302 nct6775_write_value(data, data->REG_TARGET[nr],
2303 data->target_speed[nr] & 0xff);
2304 if (data->REG_TOLERANCE_H) {
2305 reg = (data->target_speed[nr] >> 8) & 0x0f;
2306 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2307 nct6775_write_value(data,
2308 data->REG_TOLERANCE_H[nr],
2309 reg);
2310 }
2311 break;
2312 case thermal_cruise:
2313 nct6775_write_value(data, data->REG_TARGET[nr],
2314 data->target_temp[nr]);
2315 /* intentional */
2316 default:
2317 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2318 reg = (reg & ~data->tolerance_mask) |
2319 data->temp_tolerance[0][nr];
2320 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2321 break;
2322 }
2323}
2324
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002325static ssize_t
2326show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2327{
2328 struct nct6775_data *data = nct6775_update_device(dev);
2329 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2330
2331 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2332}
2333
2334static ssize_t
2335store_pwm_enable(struct device *dev, struct device_attribute *attr,
2336 const char *buf, size_t count)
2337{
2338 struct nct6775_data *data = dev_get_drvdata(dev);
2339 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2340 int nr = sattr->index;
2341 unsigned long val;
2342 int err;
2343 u16 reg;
2344
2345 err = kstrtoul(buf, 10, &val);
2346 if (err < 0)
2347 return err;
2348
2349 if (val > sf4)
2350 return -EINVAL;
2351
2352 if (val == sf3 && data->kind != nct6775)
2353 return -EINVAL;
2354
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002355 if (val == sf4 && check_trip_points(data, nr)) {
2356 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2357 dev_err(dev, "Adjust trip points and try again\n");
2358 return -EINVAL;
2359 }
2360
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002361 mutex_lock(&data->update_lock);
2362 data->pwm_enable[nr] = val;
2363 if (val == off) {
2364 /*
2365 * turn off pwm control: select manual mode, set pwm to maximum
2366 */
2367 data->pwm[0][nr] = 255;
2368 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2369 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002370 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002371 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2372 reg &= 0x0f;
2373 reg |= pwm_enable_to_reg(val) << 4;
2374 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2375 mutex_unlock(&data->update_lock);
2376 return count;
2377}
2378
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002379static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002380show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002381{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002382 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002383
2384 for (i = 0; i < NUM_TEMP; i++) {
2385 if (!(data->have_temp & (1 << i)))
2386 continue;
2387 if (src == data->temp_src[i]) {
2388 sel = i + 1;
2389 break;
2390 }
2391 }
2392
2393 return sprintf(buf, "%d\n", sel);
2394}
2395
2396static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002397show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2398{
2399 struct nct6775_data *data = nct6775_update_device(dev);
2400 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2401 int index = sattr->index;
2402
2403 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2404}
2405
2406static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002407store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2408 const char *buf, size_t count)
2409{
2410 struct nct6775_data *data = nct6775_update_device(dev);
2411 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2412 int nr = sattr->index;
2413 unsigned long val;
2414 int err, reg, src;
2415
2416 err = kstrtoul(buf, 10, &val);
2417 if (err < 0)
2418 return err;
2419 if (val == 0 || val > NUM_TEMP)
2420 return -EINVAL;
2421 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2422 return -EINVAL;
2423
2424 mutex_lock(&data->update_lock);
2425 src = data->temp_src[val - 1];
2426 data->pwm_temp_sel[nr] = src;
2427 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2428 reg &= 0xe0;
2429 reg |= src;
2430 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2431 mutex_unlock(&data->update_lock);
2432
2433 return count;
2434}
2435
2436static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002437show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2438 char *buf)
2439{
2440 struct nct6775_data *data = nct6775_update_device(dev);
2441 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2442 int index = sattr->index;
2443
2444 return show_pwm_temp_sel_common(data, buf,
2445 data->pwm_weight_temp_sel[index]);
2446}
2447
2448static ssize_t
2449store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2450 const char *buf, size_t count)
2451{
2452 struct nct6775_data *data = nct6775_update_device(dev);
2453 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2454 int nr = sattr->index;
2455 unsigned long val;
2456 int err, reg, src;
2457
2458 err = kstrtoul(buf, 10, &val);
2459 if (err < 0)
2460 return err;
2461 if (val > NUM_TEMP)
2462 return -EINVAL;
2463 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2464 !data->temp_src[val - 1]))
2465 return -EINVAL;
2466
2467 mutex_lock(&data->update_lock);
2468 if (val) {
2469 src = data->temp_src[val - 1];
2470 data->pwm_weight_temp_sel[nr] = src;
2471 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2472 reg &= 0xe0;
2473 reg |= (src | 0x80);
2474 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2475 } else {
2476 data->pwm_weight_temp_sel[nr] = 0;
2477 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2478 reg &= 0x7f;
2479 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2480 }
2481 mutex_unlock(&data->update_lock);
2482
2483 return count;
2484}
2485
2486static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002487show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2488{
2489 struct nct6775_data *data = nct6775_update_device(dev);
2490 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2491
2492 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2493}
2494
2495static ssize_t
2496store_target_temp(struct device *dev, struct device_attribute *attr,
2497 const char *buf, size_t count)
2498{
2499 struct nct6775_data *data = dev_get_drvdata(dev);
2500 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2501 int nr = sattr->index;
2502 unsigned long val;
2503 int err;
2504
2505 err = kstrtoul(buf, 10, &val);
2506 if (err < 0)
2507 return err;
2508
2509 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2510 data->target_temp_mask);
2511
2512 mutex_lock(&data->update_lock);
2513 data->target_temp[nr] = val;
2514 pwm_update_registers(data, nr);
2515 mutex_unlock(&data->update_lock);
2516 return count;
2517}
2518
2519static ssize_t
2520show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2521{
2522 struct nct6775_data *data = nct6775_update_device(dev);
2523 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2524 int nr = sattr->index;
2525
2526 return sprintf(buf, "%d\n",
2527 fan_from_reg16(data->target_speed[nr],
2528 data->fan_div[nr]));
2529}
2530
2531static ssize_t
2532store_target_speed(struct device *dev, struct device_attribute *attr,
2533 const char *buf, size_t count)
2534{
2535 struct nct6775_data *data = dev_get_drvdata(dev);
2536 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2537 int nr = sattr->index;
2538 unsigned long val;
2539 int err;
2540 u16 speed;
2541
2542 err = kstrtoul(buf, 10, &val);
2543 if (err < 0)
2544 return err;
2545
2546 val = clamp_val(val, 0, 1350000U);
2547 speed = fan_to_reg(val, data->fan_div[nr]);
2548
2549 mutex_lock(&data->update_lock);
2550 data->target_speed[nr] = speed;
2551 pwm_update_registers(data, nr);
2552 mutex_unlock(&data->update_lock);
2553 return count;
2554}
2555
2556static ssize_t
2557show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2558 char *buf)
2559{
2560 struct nct6775_data *data = nct6775_update_device(dev);
2561 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2562 int nr = sattr->nr;
2563 int index = sattr->index;
2564
2565 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2566}
2567
2568static ssize_t
2569store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2570 const char *buf, size_t count)
2571{
2572 struct nct6775_data *data = dev_get_drvdata(dev);
2573 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2574 int nr = sattr->nr;
2575 int index = sattr->index;
2576 unsigned long val;
2577 int err;
2578
2579 err = kstrtoul(buf, 10, &val);
2580 if (err < 0)
2581 return err;
2582
2583 /* Limit tolerance as needed */
2584 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2585
2586 mutex_lock(&data->update_lock);
2587 data->temp_tolerance[index][nr] = val;
2588 if (index)
2589 pwm_update_registers(data, nr);
2590 else
2591 nct6775_write_value(data,
2592 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2593 val);
2594 mutex_unlock(&data->update_lock);
2595 return count;
2596}
2597
2598/*
2599 * Fan speed tolerance is a tricky beast, since the associated register is
2600 * a tick counter, but the value is reported and configured as rpm.
2601 * Compute resulting low and high rpm values and report the difference.
2602 */
2603static ssize_t
2604show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2605 char *buf)
2606{
2607 struct nct6775_data *data = nct6775_update_device(dev);
2608 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2609 int nr = sattr->index;
2610 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2611 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2612 int tolerance;
2613
2614 if (low <= 0)
2615 low = 1;
2616 if (high > 0xffff)
2617 high = 0xffff;
2618 if (high < low)
2619 high = low;
2620
2621 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2622 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2623
2624 return sprintf(buf, "%d\n", tolerance);
2625}
2626
2627static ssize_t
2628store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2629 const char *buf, size_t count)
2630{
2631 struct nct6775_data *data = dev_get_drvdata(dev);
2632 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2633 int nr = sattr->index;
2634 unsigned long val;
2635 int err;
2636 int low, high;
2637
2638 err = kstrtoul(buf, 10, &val);
2639 if (err < 0)
2640 return err;
2641
2642 high = fan_from_reg16(data->target_speed[nr],
2643 data->fan_div[nr]) + val;
2644 low = fan_from_reg16(data->target_speed[nr],
2645 data->fan_div[nr]) - val;
2646 if (low <= 0)
2647 low = 1;
2648 if (high < low)
2649 high = low;
2650
2651 val = (fan_to_reg(low, data->fan_div[nr]) -
2652 fan_to_reg(high, data->fan_div[nr])) / 2;
2653
2654 /* Limit tolerance as needed */
2655 val = clamp_val(val, 0, data->speed_tolerance_limit);
2656
2657 mutex_lock(&data->update_lock);
2658 data->target_speed_tolerance[nr] = val;
2659 pwm_update_registers(data, nr);
2660 mutex_unlock(&data->update_lock);
2661 return count;
2662}
2663
Guenter Roeckf73cf632013-03-18 09:22:50 -07002664SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2665SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2666 store_pwm_mode, 0);
2667SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2668 store_pwm_enable, 0);
2669SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2670 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2671SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2672 show_target_temp, store_target_temp, 0);
2673SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2674 show_target_speed, store_target_speed, 0);
2675SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2676 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002677
2678/* Smart Fan registers */
2679
2680static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002681show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2682{
2683 struct nct6775_data *data = nct6775_update_device(dev);
2684 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2685 int nr = sattr->nr;
2686 int index = sattr->index;
2687
2688 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2689}
2690
2691static ssize_t
2692store_weight_temp(struct device *dev, struct device_attribute *attr,
2693 const char *buf, size_t count)
2694{
2695 struct nct6775_data *data = dev_get_drvdata(dev);
2696 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2697 int nr = sattr->nr;
2698 int index = sattr->index;
2699 unsigned long val;
2700 int err;
2701
2702 err = kstrtoul(buf, 10, &val);
2703 if (err < 0)
2704 return err;
2705
2706 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2707
2708 mutex_lock(&data->update_lock);
2709 data->weight_temp[index][nr] = val;
2710 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2711 mutex_unlock(&data->update_lock);
2712 return count;
2713}
2714
Guenter Roeckf73cf632013-03-18 09:22:50 -07002715SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2716 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2717SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2718 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2719SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2720 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2721SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2722 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2723SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2724 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2725SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2726 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002727
2728static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002729show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2730{
2731 struct nct6775_data *data = nct6775_update_device(dev);
2732 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2733 int nr = sattr->nr;
2734 int index = sattr->index;
2735
2736 return sprintf(buf, "%d\n",
2737 step_time_from_reg(data->fan_time[index][nr],
2738 data->pwm_mode[nr]));
2739}
2740
2741static ssize_t
2742store_fan_time(struct device *dev, struct device_attribute *attr,
2743 const char *buf, size_t count)
2744{
2745 struct nct6775_data *data = dev_get_drvdata(dev);
2746 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2747 int nr = sattr->nr;
2748 int index = sattr->index;
2749 unsigned long val;
2750 int err;
2751
2752 err = kstrtoul(buf, 10, &val);
2753 if (err < 0)
2754 return err;
2755
2756 val = step_time_to_reg(val, data->pwm_mode[nr]);
2757 mutex_lock(&data->update_lock);
2758 data->fan_time[index][nr] = val;
2759 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2760 mutex_unlock(&data->update_lock);
2761 return count;
2762}
2763
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002764static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002765show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2766{
2767 struct nct6775_data *data = nct6775_update_device(dev);
2768 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2769
2770 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2771}
2772
2773static ssize_t
2774store_auto_pwm(struct device *dev, struct device_attribute *attr,
2775 const char *buf, size_t count)
2776{
2777 struct nct6775_data *data = dev_get_drvdata(dev);
2778 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2779 int nr = sattr->nr;
2780 int point = sattr->index;
2781 unsigned long val;
2782 int err;
2783 u8 reg;
2784
2785 err = kstrtoul(buf, 10, &val);
2786 if (err < 0)
2787 return err;
2788 if (val > 255)
2789 return -EINVAL;
2790
2791 if (point == data->auto_pwm_num) {
2792 if (data->kind != nct6775 && !val)
2793 return -EINVAL;
2794 if (data->kind != nct6779 && val)
2795 val = 0xff;
2796 }
2797
2798 mutex_lock(&data->update_lock);
2799 data->auto_pwm[nr][point] = val;
2800 if (point < data->auto_pwm_num) {
2801 nct6775_write_value(data,
2802 NCT6775_AUTO_PWM(data, nr, point),
2803 data->auto_pwm[nr][point]);
2804 } else {
2805 switch (data->kind) {
2806 case nct6775:
2807 /* disable if needed (pwm == 0) */
2808 reg = nct6775_read_value(data,
2809 NCT6775_REG_CRITICAL_ENAB[nr]);
2810 if (val)
2811 reg |= 0x02;
2812 else
2813 reg &= ~0x02;
2814 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2815 reg);
2816 break;
2817 case nct6776:
2818 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002819 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002820 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002821 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002822 case nct6792:
Guenter Roeck6c009502012-07-01 08:23:15 -07002823 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002824 val);
2825 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002826 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002827 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002828 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002829 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002830 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002831 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002832 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002833 reg);
2834 break;
2835 }
2836 }
2837 mutex_unlock(&data->update_lock);
2838 return count;
2839}
2840
2841static ssize_t
2842show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2843{
2844 struct nct6775_data *data = nct6775_update_device(dev);
2845 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2846 int nr = sattr->nr;
2847 int point = sattr->index;
2848
2849 /*
2850 * We don't know for sure if the temperature is signed or unsigned.
2851 * Assume it is unsigned.
2852 */
2853 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2854}
2855
2856static ssize_t
2857store_auto_temp(struct device *dev, struct device_attribute *attr,
2858 const char *buf, size_t count)
2859{
2860 struct nct6775_data *data = dev_get_drvdata(dev);
2861 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2862 int nr = sattr->nr;
2863 int point = sattr->index;
2864 unsigned long val;
2865 int err;
2866
2867 err = kstrtoul(buf, 10, &val);
2868 if (err)
2869 return err;
2870 if (val > 255000)
2871 return -EINVAL;
2872
2873 mutex_lock(&data->update_lock);
2874 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2875 if (point < data->auto_pwm_num) {
2876 nct6775_write_value(data,
2877 NCT6775_AUTO_TEMP(data, nr, point),
2878 data->auto_temp[nr][point]);
2879 } else {
2880 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2881 data->auto_temp[nr][point]);
2882 }
2883 mutex_unlock(&data->update_lock);
2884 return count;
2885}
2886
Guenter Roeckf73cf632013-03-18 09:22:50 -07002887static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2888 struct attribute *attr, int index)
2889{
2890 struct device *dev = container_of(kobj, struct device, kobj);
2891 struct nct6775_data *data = dev_get_drvdata(dev);
2892 int pwm = index / 36; /* pwm index */
2893 int nr = index % 36; /* attribute index */
2894
2895 if (!(data->has_pwm & (1 << pwm)))
2896 return 0;
2897
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002898 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2899 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2900 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002901 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2902 return 0;
2903 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2904 return 0;
2905 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2906 return 0;
2907
2908 if (nr >= 22 && nr <= 35) { /* auto point */
2909 int api = (nr - 22) / 2; /* auto point index */
2910
2911 if (api > data->auto_pwm_num)
2912 return 0;
2913 }
2914 return attr->mode;
2915}
2916
2917SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2918 show_fan_time, store_fan_time, 0, 0);
2919SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2920 show_fan_time, store_fan_time, 0, 1);
2921SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2922 show_fan_time, store_fan_time, 0, 2);
2923SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2924 store_pwm, 0, 1);
2925SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2926 store_pwm, 0, 2);
2927SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2928 show_temp_tolerance, store_temp_tolerance, 0, 0);
2929SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2930 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2931 0, 1);
2932
2933SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2934 0, 3);
2935
2936SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2937 store_pwm, 0, 4);
2938
2939SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2940 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2941SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2942 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2943
2944SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2945 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2946SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2947 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2948
2949SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2950 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2951SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2952 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2953
2954SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2955 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2956SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2957 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2958
2959SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2960 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2961SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2962 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2963
2964SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2965 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2966SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2967 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2968
2969SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2970 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2971SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2972 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2973
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002974/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002975 * nct6775_pwm_is_visible uses the index into the following array
2976 * to determine if attributes should be created or not.
2977 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002978 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002979static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2980 &sensor_dev_template_pwm,
2981 &sensor_dev_template_pwm_mode,
2982 &sensor_dev_template_pwm_enable,
2983 &sensor_dev_template_pwm_temp_sel,
2984 &sensor_dev_template_pwm_temp_tolerance,
2985 &sensor_dev_template_pwm_crit_temp_tolerance,
2986 &sensor_dev_template_pwm_target_temp,
2987 &sensor_dev_template_fan_target,
2988 &sensor_dev_template_fan_tolerance,
2989 &sensor_dev_template_pwm_stop_time,
2990 &sensor_dev_template_pwm_step_up_time,
2991 &sensor_dev_template_pwm_step_down_time,
2992 &sensor_dev_template_pwm_start,
2993 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002994 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002995 &sensor_dev_template_pwm_weight_temp_step,
2996 &sensor_dev_template_pwm_weight_temp_step_tol,
2997 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002998 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002999 &sensor_dev_template_pwm_max, /* 19 */
3000 &sensor_dev_template_pwm_step, /* 20 */
3001 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3002 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3003 &sensor_dev_template_pwm_auto_point1_temp,
3004 &sensor_dev_template_pwm_auto_point2_pwm,
3005 &sensor_dev_template_pwm_auto_point2_temp,
3006 &sensor_dev_template_pwm_auto_point3_pwm,
3007 &sensor_dev_template_pwm_auto_point3_temp,
3008 &sensor_dev_template_pwm_auto_point4_pwm,
3009 &sensor_dev_template_pwm_auto_point4_temp,
3010 &sensor_dev_template_pwm_auto_point5_pwm,
3011 &sensor_dev_template_pwm_auto_point5_temp,
3012 &sensor_dev_template_pwm_auto_point6_pwm,
3013 &sensor_dev_template_pwm_auto_point6_temp,
3014 &sensor_dev_template_pwm_auto_point7_pwm,
3015 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003016
Guenter Roeckf73cf632013-03-18 09:22:50 -07003017 NULL
3018};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003019
Guenter Roeckf73cf632013-03-18 09:22:50 -07003020static struct sensor_template_group nct6775_pwm_template_group = {
3021 .templates = nct6775_attributes_pwm_template,
3022 .is_visible = nct6775_pwm_is_visible,
3023 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003024};
3025
3026static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003027show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3028{
3029 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003030
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003031 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3032}
3033
3034static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3035
Guenter Roecka6bd5872012-12-04 03:13:34 -08003036/* Case open detection */
3037
3038static ssize_t
3039clear_caseopen(struct device *dev, struct device_attribute *attr,
3040 const char *buf, size_t count)
3041{
3042 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003043 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3044 unsigned long val;
3045 u8 reg;
3046 int ret;
3047
3048 if (kstrtoul(buf, 10, &val) || val != 0)
3049 return -EINVAL;
3050
3051 mutex_lock(&data->update_lock);
3052
3053 /*
3054 * Use CR registers to clear caseopen status.
3055 * The CR registers are the same for all chips, and not all chips
3056 * support clearing the caseopen status through "regular" registers.
3057 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003058 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003059 if (ret) {
3060 count = ret;
3061 goto error;
3062 }
3063
Guenter Roeckdf612d52013-07-08 13:15:04 -07003064 superio_select(data->sioreg, NCT6775_LD_ACPI);
3065 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003066 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003067 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003068 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003069 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3070 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003071
3072 data->valid = false; /* Force cache refresh */
3073error:
3074 mutex_unlock(&data->update_lock);
3075 return count;
3076}
3077
Guenter Roeckf73cf632013-03-18 09:22:50 -07003078static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3079 clear_caseopen, INTRUSION_ALARM_BASE);
3080static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3081 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003082static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3083 store_beep, INTRUSION_ALARM_BASE);
3084static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3085 store_beep, INTRUSION_ALARM_BASE + 1);
3086static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3087 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003088
3089static umode_t nct6775_other_is_visible(struct kobject *kobj,
3090 struct attribute *attr, int index)
3091{
3092 struct device *dev = container_of(kobj, struct device, kobj);
3093 struct nct6775_data *data = dev_get_drvdata(dev);
3094
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003095 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003096 return 0;
3097
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003098 if (index == 1 || index == 2) {
3099 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003100 return 0;
3101 }
3102
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003103 if (index == 3 || index == 4) {
3104 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003105 return 0;
3106 }
3107
Guenter Roeckf73cf632013-03-18 09:22:50 -07003108 return attr->mode;
3109}
3110
3111/*
3112 * nct6775_other_is_visible uses the index into the following array
3113 * to determine if attributes should be created or not.
3114 * Any change in order or content must be matched.
3115 */
3116static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003117 &dev_attr_cpu0_vid.attr, /* 0 */
3118 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3119 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3120 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3121 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3122 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003123
3124 NULL
3125};
3126
3127static const struct attribute_group nct6775_group_other = {
3128 .attrs = nct6775_attributes_other,
3129 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003130};
3131
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003132static inline void nct6775_init_device(struct nct6775_data *data)
3133{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003134 int i;
3135 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003136
3137 /* Start monitoring if needed */
3138 if (data->REG_CONFIG) {
3139 tmp = nct6775_read_value(data, data->REG_CONFIG);
3140 if (!(tmp & 0x01))
3141 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3142 }
3143
Guenter Roeckaa136e52012-12-04 03:26:05 -08003144 /* Enable temperature sensors if needed */
3145 for (i = 0; i < NUM_TEMP; i++) {
3146 if (!(data->have_temp & (1 << i)))
3147 continue;
3148 if (!data->reg_temp_config[i])
3149 continue;
3150 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3151 if (tmp & 0x01)
3152 nct6775_write_value(data, data->reg_temp_config[i],
3153 tmp & 0xfe);
3154 }
3155
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003156 /* Enable VBAT monitoring if needed */
3157 tmp = nct6775_read_value(data, data->REG_VBAT);
3158 if (!(tmp & 0x01))
3159 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003160
3161 diode = nct6775_read_value(data, data->REG_DIODE);
3162
3163 for (i = 0; i < data->temp_fixed_num; i++) {
3164 if (!(data->have_temp_fixed & (1 << i)))
3165 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003166 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3167 data->temp_type[i]
3168 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003169 else /* thermistor */
3170 data->temp_type[i] = 4;
3171 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003172}
3173
Guenter Roeckf73cf632013-03-18 09:22:50 -07003174static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003175nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003176{
David Bartley578ab5f2013-06-24 22:28:28 -07003177 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3178 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003179 int sioreg = data->sioreg;
3180 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003181
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003182 /* Store SIO_REG_ENABLE for use during resume */
3183 superio_select(sioreg, NCT6775_LD_HWM);
3184 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3185
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003186 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3187 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003188 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003189
3190 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003191 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003192
3193 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003194 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003195 fan4min = false;
3196 fan5pin = false;
3197 fan6pin = false;
3198 pwm4pin = false;
3199 pwm5pin = false;
3200 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003201 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003202 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003203 const char *board_vendor, *board_name;
3204
3205 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3206 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3207
3208 if (board_name && board_vendor &&
3209 !strcmp(board_vendor, "ASRock")) {
3210 /*
3211 * Auxiliary fan monitoring is not enabled on ASRock
3212 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3213 * Observed with BIOS version 2.00.
3214 */
3215 if (!strcmp(board_name, "Z77 Pro4-M")) {
3216 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3217 data->sio_reg_enable |= 0xe0;
3218 superio_outb(sioreg, SIO_REG_ENABLE,
3219 data->sio_reg_enable);
3220 }
3221 }
3222 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003223
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003224 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003225 fan3pin = gpok;
3226 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003227 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003228
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003229 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003230 fan4pin = gpok;
3231 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003232 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003233
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003234 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003235 fan5pin = gpok;
3236 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003237 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003238
3239 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003240 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003241 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003242 pwm4pin = false;
3243 pwm5pin = false;
3244 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003245 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003246 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003247 fan3pin = !(regval & 0x80);
3248 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003249
3250 fan4pin = false;
3251 fan4min = false;
3252 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003253 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003254 pwm4pin = false;
3255 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003256 pwm6pin = false;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003257 } else { /* NCT6779D, NCT6791D, or NCT6792D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003258 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003259
3260 fan3pin = !(regval & (1 << 5));
3261 fan4pin = !(regval & (1 << 6));
3262 fan5pin = !(regval & (1 << 7));
3263
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003264 pwm3pin = !(regval & (1 << 0));
3265 pwm4pin = !(regval & (1 << 1));
3266 pwm5pin = !(regval & (1 << 2));
3267
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003268 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003269
Guenter Roeck8aefb932014-11-16 09:50:04 -08003270 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003271 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003272 fan6pin = (regval & (1 << 1));
3273 pwm6pin = (regval & (1 << 0));
3274 } else { /* NCT6779D */
3275 fan6pin = false;
3276 pwm6pin = false;
3277 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003278 }
3279
David Bartley578ab5f2013-06-24 22:28:28 -07003280 /* fan 1 and 2 (0x03) are always present */
3281 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3282 (fan5pin << 4) | (fan6pin << 5);
3283 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3284 (fan5pin << 4);
3285 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3286 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003287}
3288
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003289static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3290 int *available, int *mask)
3291{
3292 int i;
3293 u8 src;
3294
3295 for (i = 0; i < data->pwm_num && *available; i++) {
3296 int index;
3297
3298 if (!regp[i])
3299 continue;
3300 src = nct6775_read_value(data, regp[i]);
3301 src &= 0x1f;
3302 if (!src || (*mask & (1 << src)))
3303 continue;
3304 if (src >= data->temp_label_num ||
3305 !strlen(data->temp_label[src]))
3306 continue;
3307
3308 index = __ffs(*available);
3309 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3310 *available &= ~(1 << index);
3311 *mask |= 1 << src;
3312 }
3313}
3314
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003315static int nct6775_probe(struct platform_device *pdev)
3316{
3317 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003318 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003319 struct nct6775_data *data;
3320 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003321 int i, s, err = 0;
3322 int src, mask, available;
3323 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003324 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003325 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003326 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003327 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003328 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003329 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003330 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003331
3332 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3333 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3334 DRVNAME))
3335 return -EBUSY;
3336
3337 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3338 GFP_KERNEL);
3339 if (!data)
3340 return -ENOMEM;
3341
3342 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003343 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003344 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003345 mutex_init(&data->update_lock);
3346 data->name = nct6775_device_names[data->kind];
3347 data->bank = 0xff; /* Force initial bank selection */
3348 platform_set_drvdata(pdev, data);
3349
3350 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003351 case nct6106:
3352 data->in_num = 9;
3353 data->pwm_num = 3;
3354 data->auto_pwm_num = 4;
3355 data->temp_fixed_num = 3;
3356 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003357 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003358
3359 data->fan_from_reg = fan_from_reg13;
3360 data->fan_from_reg_min = fan_from_reg13;
3361
3362 data->temp_label = nct6776_temp_label;
3363 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3364
3365 data->REG_VBAT = NCT6106_REG_VBAT;
3366 data->REG_DIODE = NCT6106_REG_DIODE;
3367 data->DIODE_MASK = NCT6106_DIODE_MASK;
3368 data->REG_VIN = NCT6106_REG_IN;
3369 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3370 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3371 data->REG_TARGET = NCT6106_REG_TARGET;
3372 data->REG_FAN = NCT6106_REG_FAN;
3373 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3374 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3375 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3376 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3377 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3378 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3379 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3380 data->REG_PWM[0] = NCT6106_REG_PWM;
3381 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3382 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3383 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3384 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3385 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3386 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3387 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3388 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3389 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3390 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3391 data->REG_CRITICAL_TEMP_TOLERANCE
3392 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3393 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3394 data->CRITICAL_PWM_ENABLE_MASK
3395 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3396 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3397 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3398 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3399 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3400 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3401 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3402 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3403 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3404 data->REG_ALARM = NCT6106_REG_ALARM;
3405 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003406 data->REG_BEEP = NCT6106_REG_BEEP;
3407 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003408
3409 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003410 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003411 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003412 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003413 reg_temp_over = NCT6106_REG_TEMP_OVER;
3414 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3415 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3416 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3417 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003418 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3419 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003420
3421 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003422 case nct6775:
3423 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003424 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003425 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003426 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003427 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003428 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003429 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003430
3431 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003432 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003433
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003434 data->fan_from_reg = fan_from_reg16;
3435 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003436 data->target_temp_mask = 0x7f;
3437 data->tolerance_mask = 0x0f;
3438 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003439
Guenter Roeckaa136e52012-12-04 03:26:05 -08003440 data->temp_label = nct6775_temp_label;
3441 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3442
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003443 data->REG_CONFIG = NCT6775_REG_CONFIG;
3444 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003445 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003446 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003447 data->REG_VIN = NCT6775_REG_IN;
3448 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3449 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003450 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003451 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003452 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003453 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003454 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003455 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003456 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3457 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3458 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003459 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003460 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3461 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3462 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3463 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003464 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003465 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3466 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3467 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003468 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3469 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3470 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3471 data->REG_CRITICAL_TEMP_TOLERANCE
3472 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003473 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3474 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003475 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003476 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3477 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3478 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3479 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003480 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003481 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003482
3483 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003484 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003485 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003486 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003487 reg_temp_over = NCT6775_REG_TEMP_OVER;
3488 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3489 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3490 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3491 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3492
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003493 break;
3494 case nct6776:
3495 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003496 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003497 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003498 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003499 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003500 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003501 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003502
3503 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003504 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003505
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003506 data->fan_from_reg = fan_from_reg13;
3507 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003508 data->target_temp_mask = 0xff;
3509 data->tolerance_mask = 0x07;
3510 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003511
Guenter Roeckaa136e52012-12-04 03:26:05 -08003512 data->temp_label = nct6776_temp_label;
3513 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3514
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003515 data->REG_CONFIG = NCT6775_REG_CONFIG;
3516 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003517 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003518 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003519 data->REG_VIN = NCT6775_REG_IN;
3520 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3521 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003522 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003523 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003524 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003525 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003526 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003527 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003528 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3529 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3530 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3531 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003532 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003533 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3534 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003535 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3536 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003537 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3538 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3539 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003540 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3541 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3542 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3543 data->REG_CRITICAL_TEMP_TOLERANCE
3544 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003545 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3546 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003547 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003548 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3549 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3550 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3551 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003553 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003554
3555 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003556 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003557 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003558 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003559 reg_temp_over = NCT6775_REG_TEMP_OVER;
3560 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3561 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3562 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3563 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3564
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003565 break;
3566 case nct6779:
3567 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003568 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003569 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003570 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003571 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003572 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003573 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003574
3575 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003576 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003577
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003578 data->fan_from_reg = fan_from_reg13;
3579 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003580 data->target_temp_mask = 0xff;
3581 data->tolerance_mask = 0x07;
3582 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003583
Guenter Roeckaa136e52012-12-04 03:26:05 -08003584 data->temp_label = nct6779_temp_label;
3585 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3586
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003587 data->REG_CONFIG = NCT6775_REG_CONFIG;
3588 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003589 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003590 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003591 data->REG_VIN = NCT6779_REG_IN;
3592 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3593 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003594 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003595 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003596 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003597 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003598 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003599 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003600 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3601 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3602 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3603 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003604 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003605 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3606 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003607 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3608 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003609 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3610 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3611 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003612 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3613 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3614 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3615 data->REG_CRITICAL_TEMP_TOLERANCE
3616 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003617 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3618 data->CRITICAL_PWM_ENABLE_MASK
3619 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3620 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003621 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3622 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003623 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003624 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3625 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3626 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3627 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003628 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003629 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003630
3631 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003632 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003633 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003634 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003635 reg_temp_over = NCT6779_REG_TEMP_OVER;
3636 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3637 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3638 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3639 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3640
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003641 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003642 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003643 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003644 data->in_num = 15;
3645 data->pwm_num = 6;
3646 data->auto_pwm_num = 4;
3647 data->has_fan_div = false;
3648 data->temp_fixed_num = 6;
3649 data->num_temp_alarms = 2;
3650 data->num_temp_beeps = 2;
3651
3652 data->ALARM_BITS = NCT6791_ALARM_BITS;
3653 data->BEEP_BITS = NCT6779_BEEP_BITS;
3654
3655 data->fan_from_reg = fan_from_reg13;
3656 data->fan_from_reg_min = fan_from_reg13;
3657 data->target_temp_mask = 0xff;
3658 data->tolerance_mask = 0x07;
3659 data->speed_tolerance_limit = 63;
3660
3661 data->temp_label = nct6779_temp_label;
3662 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3663
3664 data->REG_CONFIG = NCT6775_REG_CONFIG;
3665 data->REG_VBAT = NCT6775_REG_VBAT;
3666 data->REG_DIODE = NCT6775_REG_DIODE;
3667 data->DIODE_MASK = NCT6775_DIODE_MASK;
3668 data->REG_VIN = NCT6779_REG_IN;
3669 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3670 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3671 data->REG_TARGET = NCT6775_REG_TARGET;
3672 data->REG_FAN = NCT6779_REG_FAN;
3673 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3674 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3675 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3676 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3677 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3678 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3679 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3680 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3681 data->REG_PWM[0] = NCT6775_REG_PWM;
3682 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3683 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003684 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3685 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003686 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3687 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3688 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3689 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3690 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3691 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3692 data->REG_CRITICAL_TEMP_TOLERANCE
3693 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3694 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3695 data->CRITICAL_PWM_ENABLE_MASK
3696 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3697 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3698 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3699 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3700 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003701 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3702 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3703 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3704 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003705 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003706 if (data->kind == nct6791)
3707 data->REG_BEEP = NCT6776_REG_BEEP;
3708 else
3709 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003710
3711 reg_temp = NCT6779_REG_TEMP;
3712 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003713 if (data->kind == nct6791) {
3714 reg_temp_mon = NCT6779_REG_TEMP_MON;
3715 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3716 } else {
3717 reg_temp_mon = NCT6792_REG_TEMP_MON;
3718 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3719 }
David Bartley578ab5f2013-06-24 22:28:28 -07003720 reg_temp_over = NCT6779_REG_TEMP_OVER;
3721 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3722 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3723 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3724 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3725
3726 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003727 default:
3728 return -ENODEV;
3729 }
3730 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003731 data->have_temp = 0;
3732
3733 /*
3734 * On some boards, not all available temperature sources are monitored,
3735 * even though some of the monitoring registers are unused.
3736 * Get list of unused monitoring registers, then detect if any fan
3737 * controls are configured to use unmonitored temperature sources.
3738 * If so, assign the unmonitored temperature sources to available
3739 * monitoring registers.
3740 */
3741 mask = 0;
3742 available = 0;
3743 for (i = 0; i < num_reg_temp; i++) {
3744 if (reg_temp[i] == 0)
3745 continue;
3746
3747 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3748 if (!src || (mask & (1 << src)))
3749 available |= 1 << i;
3750
3751 mask |= 1 << src;
3752 }
3753
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003754 /*
3755 * Now find unmonitored temperature registers and enable monitoring
3756 * if additional monitoring registers are available.
3757 */
3758 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3759 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3760
Guenter Roeckaa136e52012-12-04 03:26:05 -08003761 mask = 0;
3762 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3763 for (i = 0; i < num_reg_temp; i++) {
3764 if (reg_temp[i] == 0)
3765 continue;
3766
3767 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[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_SOURCE[i], reg_temp[i]);
3776 continue;
3777 }
3778
3779 mask |= 1 << src;
3780
3781 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3782 if (src <= data->temp_fixed_num) {
3783 data->have_temp |= 1 << (src - 1);
3784 data->have_temp_fixed |= 1 << (src - 1);
3785 data->reg_temp[0][src - 1] = reg_temp[i];
3786 data->reg_temp[1][src - 1] = reg_temp_over[i];
3787 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003788 if (reg_temp_crit_h && reg_temp_crit_h[i])
3789 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3790 else if (reg_temp_crit[src - 1])
3791 data->reg_temp[3][src - 1]
3792 = reg_temp_crit[src - 1];
3793 if (reg_temp_crit_l && reg_temp_crit_l[i])
3794 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003795 data->reg_temp_config[src - 1] = reg_temp_config[i];
3796 data->temp_src[src - 1] = src;
3797 continue;
3798 }
3799
3800 if (s >= NUM_TEMP)
3801 continue;
3802
3803 /* Use dynamic index for other sources */
3804 data->have_temp |= 1 << s;
3805 data->reg_temp[0][s] = reg_temp[i];
3806 data->reg_temp[1][s] = reg_temp_over[i];
3807 data->reg_temp[2][s] = reg_temp_hyst[i];
3808 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003809 if (reg_temp_crit_h && reg_temp_crit_h[i])
3810 data->reg_temp[3][s] = reg_temp_crit_h[i];
3811 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003812 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003813 if (reg_temp_crit_l && reg_temp_crit_l[i])
3814 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003815
3816 data->temp_src[s] = src;
3817 s++;
3818 }
3819
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003820 /*
3821 * Repeat with temperatures used for fan control.
3822 * This set of registers does not support limits.
3823 */
3824 for (i = 0; i < num_reg_temp_mon; i++) {
3825 if (reg_temp_mon[i] == 0)
3826 continue;
3827
3828 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3829 if (!src || (mask & (1 << src)))
3830 continue;
3831
3832 if (src >= data->temp_label_num ||
3833 !strlen(data->temp_label[src])) {
3834 dev_info(dev,
3835 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3836 src, i, data->REG_TEMP_SEL[i],
3837 reg_temp_mon[i]);
3838 continue;
3839 }
3840
3841 mask |= 1 << src;
3842
3843 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3844 if (src <= data->temp_fixed_num) {
3845 if (data->have_temp & (1 << (src - 1)))
3846 continue;
3847 data->have_temp |= 1 << (src - 1);
3848 data->have_temp_fixed |= 1 << (src - 1);
3849 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3850 data->temp_src[src - 1] = src;
3851 continue;
3852 }
3853
3854 if (s >= NUM_TEMP)
3855 continue;
3856
3857 /* Use dynamic index for other sources */
3858 data->have_temp |= 1 << s;
3859 data->reg_temp[0][s] = reg_temp_mon[i];
3860 data->temp_src[s] = src;
3861 s++;
3862 }
3863
Guenter Roeckaa136e52012-12-04 03:26:05 -08003864#ifdef USE_ALTERNATE
3865 /*
3866 * Go through the list of alternate temp registers and enable
3867 * if possible.
3868 * The temperature is already monitored if the respective bit in <mask>
3869 * is set.
3870 */
3871 for (i = 0; i < data->temp_label_num - 1; i++) {
3872 if (!reg_temp_alternate[i])
3873 continue;
3874 if (mask & (1 << (i + 1)))
3875 continue;
3876 if (i < data->temp_fixed_num) {
3877 if (data->have_temp & (1 << i))
3878 continue;
3879 data->have_temp |= 1 << i;
3880 data->have_temp_fixed |= 1 << i;
3881 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003882 if (i < num_reg_temp) {
3883 data->reg_temp[1][i] = reg_temp_over[i];
3884 data->reg_temp[2][i] = reg_temp_hyst[i];
3885 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003886 data->temp_src[i] = i + 1;
3887 continue;
3888 }
3889
3890 if (s >= NUM_TEMP) /* Abort if no more space */
3891 break;
3892
3893 data->have_temp |= 1 << s;
3894 data->reg_temp[0][s] = reg_temp_alternate[i];
3895 data->temp_src[s] = i + 1;
3896 s++;
3897 }
3898#endif /* USE_ALTERNATE */
3899
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003900 /* Initialize the chip */
3901 nct6775_init_device(data);
3902
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003903 err = superio_enter(sio_data->sioreg);
3904 if (err)
3905 return err;
3906
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003907 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3908 switch (data->kind) {
3909 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003910 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003911 break;
3912 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003913 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003914 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003915 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003916 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003917 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003918 case nct6792:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003919 break;
3920 }
3921
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003922 /*
3923 * Read VID value
3924 * We can get the VID input values directly at logical device D 0xe3.
3925 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003926 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003927 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3928 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3929 data->vrm = vid_which_vrm();
3930 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003931
3932 if (fan_debounce) {
3933 u8 tmp;
3934
3935 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3936 tmp = superio_inb(sio_data->sioreg,
3937 NCT6775_REG_CR_FAN_DEBOUNCE);
3938 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003939 case nct6106:
3940 tmp |= 0xe0;
3941 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003942 case nct6775:
3943 tmp |= 0x1e;
3944 break;
3945 case nct6776:
3946 case nct6779:
3947 tmp |= 0x3e;
3948 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003949 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003950 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003951 tmp |= 0x7e;
3952 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003953 }
3954 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3955 tmp);
3956 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3957 data->name);
3958 }
3959
Guenter Roeckdf612d52013-07-08 13:15:04 -07003960 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003961
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003962 superio_exit(sio_data->sioreg);
3963
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003964 /* Read fan clock dividers immediately */
3965 nct6775_init_fan_common(dev, data);
3966
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003967 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003968 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3969 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003970 if (IS_ERR(group))
3971 return PTR_ERR(group);
3972
Axel Lin55bdee62014-07-24 08:59:34 +08003973 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003974
Guenter Roeckf73cf632013-03-18 09:22:50 -07003975 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3976 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003977 if (IS_ERR(group))
3978 return PTR_ERR(group);
3979
Axel Lin55bdee62014-07-24 08:59:34 +08003980 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003981
Guenter Roeckf73cf632013-03-18 09:22:50 -07003982 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3983 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003984 if (IS_ERR(group))
3985 return PTR_ERR(group);
3986
Axel Lin55bdee62014-07-24 08:59:34 +08003987 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003988
Guenter Roeckf73cf632013-03-18 09:22:50 -07003989 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3990 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003991 if (IS_ERR(group))
3992 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003993
Axel Lin55bdee62014-07-24 08:59:34 +08003994 data->groups[num_attr_groups++] = group;
3995 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003996
Guenter Roecka150d952013-07-11 22:55:22 -07003997 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
3998 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07003999 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004000}
4001
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004002static void nct6791_enable_io_mapping(int sioaddr)
4003{
4004 int val;
4005
4006 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4007 if (val & 0x10) {
4008 pr_info("Enabling hardware monitor logical device mappings.\n");
4009 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4010 val & ~0x10);
4011 }
4012}
4013
Guenter Roeck48e93182015-02-07 08:48:49 -08004014static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004015{
4016 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004017
4018 mutex_lock(&data->update_lock);
4019 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004020 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004021 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4022 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4023 }
4024 mutex_unlock(&data->update_lock);
4025
4026 return 0;
4027}
4028
Guenter Roeck48e93182015-02-07 08:48:49 -08004029static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004030{
4031 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004032 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004033 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004034 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004035
4036 mutex_lock(&data->update_lock);
4037 data->bank = 0xff; /* Force initial bank selection */
4038
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004039 err = superio_enter(sioreg);
4040 if (err)
4041 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004042
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004043 superio_select(sioreg, NCT6775_LD_HWM);
4044 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4045 if (reg != data->sio_reg_enable)
4046 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4047
4048 if (data->kind == nct6791 || data->kind == nct6792)
4049 nct6791_enable_io_mapping(sioreg);
4050
4051 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004052
Guenter Roeck84d19d92012-12-04 08:01:39 -08004053 /* Restore limits */
4054 for (i = 0; i < data->in_num; i++) {
4055 if (!(data->have_in & (1 << i)))
4056 continue;
4057
4058 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4059 data->in[i][1]);
4060 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4061 data->in[i][2]);
4062 }
4063
Guenter Roeckc409fd42013-04-09 05:04:00 -07004064 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004065 if (!(data->has_fan_min & (1 << i)))
4066 continue;
4067
4068 nct6775_write_value(data, data->REG_FAN_MIN[i],
4069 data->fan_min[i]);
4070 }
4071
4072 for (i = 0; i < NUM_TEMP; i++) {
4073 if (!(data->have_temp & (1 << i)))
4074 continue;
4075
Guenter Roeckc409fd42013-04-09 05:04:00 -07004076 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004077 if (data->reg_temp[j][i])
4078 nct6775_write_temp(data, data->reg_temp[j][i],
4079 data->temp[j][i]);
4080 }
4081
4082 /* Restore other settings */
4083 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004084 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004085 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4086 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4087 }
4088
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004089abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004090 /* Force re-reading all values */
4091 data->valid = false;
4092 mutex_unlock(&data->update_lock);
4093
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004094 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004095}
4096
Guenter Roeck48e93182015-02-07 08:48:49 -08004097static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004098
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004099static struct platform_driver nct6775_driver = {
4100 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004101 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004102 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004103 },
4104 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004105};
4106
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004107static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004108 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004109 "NCT6775F",
4110 "NCT6776D/F",
4111 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004112 "NCT6791D",
Guenter Roeck8aefb932014-11-16 09:50:04 -08004113 "NCT6792D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004114};
4115
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004116/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004117static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004118{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004119 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004120 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004121 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004122
4123 err = superio_enter(sioaddr);
4124 if (err)
4125 return err;
4126
4127 if (force_id)
4128 val = force_id;
4129 else
4130 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4131 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4132 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004133 case SIO_NCT6106_ID:
4134 sio_data->kind = nct6106;
4135 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004136 case SIO_NCT6775_ID:
4137 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004138 break;
4139 case SIO_NCT6776_ID:
4140 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004141 break;
4142 case SIO_NCT6779_ID:
4143 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004144 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004145 case SIO_NCT6791_ID:
4146 sio_data->kind = nct6791;
4147 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004148 case SIO_NCT6792_ID:
4149 sio_data->kind = nct6792;
4150 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004151 default:
4152 if (val != 0xffff)
4153 pr_debug("unsupported chip ID: 0x%04x\n", val);
4154 superio_exit(sioaddr);
4155 return -ENODEV;
4156 }
4157
4158 /* We have a known chip, find the HWM I/O address */
4159 superio_select(sioaddr, NCT6775_LD_HWM);
4160 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4161 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004162 addr = val & IOREGION_ALIGNMENT;
4163 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004164 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4165 superio_exit(sioaddr);
4166 return -ENODEV;
4167 }
4168
4169 /* Activate logical device if needed */
4170 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4171 if (!(val & 0x01)) {
4172 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4173 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4174 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004175
Guenter Roeck8aefb932014-11-16 09:50:04 -08004176 if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004177 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004178
4179 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004180 pr_info("Found %s or compatible chip at %#x:%#x\n",
4181 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004182 sio_data->sioreg = sioaddr;
4183
Guenter Roeck698a7c22013-04-05 07:35:25 -07004184 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004185}
4186
4187/*
4188 * when Super-I/O functions move to a separate file, the Super-I/O
4189 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004190 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004191 * must keep track of the device
4192 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004193static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004194
4195static int __init sensors_nct6775_init(void)
4196{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004197 int i, err;
4198 bool found = false;
4199 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004200 struct resource res;
4201 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004202 int sioaddr[2] = { 0x2e, 0x4e };
4203
4204 err = platform_driver_register(&nct6775_driver);
4205 if (err)
4206 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004207
4208 /*
4209 * initialize sio_data->kind and sio_data->sioreg.
4210 *
4211 * when Super-I/O functions move to a separate file, the Super-I/O
4212 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4213 * nct6775 hardware monitor, and call probe()
4214 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004215 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4216 address = nct6775_find(sioaddr[i], &sio_data);
4217 if (address <= 0)
4218 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004219
Guenter Roeck698a7c22013-04-05 07:35:25 -07004220 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004221
Guenter Roeck698a7c22013-04-05 07:35:25 -07004222 pdev[i] = platform_device_alloc(DRVNAME, address);
4223 if (!pdev[i]) {
4224 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004225 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004226 }
4227
4228 err = platform_device_add_data(pdev[i], &sio_data,
4229 sizeof(struct nct6775_sio_data));
4230 if (err)
4231 goto exit_device_put;
4232
4233 memset(&res, 0, sizeof(res));
4234 res.name = DRVNAME;
4235 res.start = address + IOREGION_OFFSET;
4236 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4237 res.flags = IORESOURCE_IO;
4238
4239 err = acpi_check_resource_conflict(&res);
4240 if (err) {
4241 platform_device_put(pdev[i]);
4242 pdev[i] = NULL;
4243 continue;
4244 }
4245
4246 err = platform_device_add_resources(pdev[i], &res, 1);
4247 if (err)
4248 goto exit_device_put;
4249
4250 /* platform_device_add calls probe() */
4251 err = platform_device_add(pdev[i]);
4252 if (err)
4253 goto exit_device_put;
4254 }
4255 if (!found) {
4256 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004257 goto exit_unregister;
4258 }
4259
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004260 return 0;
4261
4262exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004263 platform_device_put(pdev[i]);
4264exit_device_unregister:
4265 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004266 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004267 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004268 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004269exit_unregister:
4270 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004271 return err;
4272}
4273
4274static void __exit sensors_nct6775_exit(void)
4275{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004276 int i;
4277
4278 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4279 if (pdev[i])
4280 platform_device_unregister(pdev[i]);
4281 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004282 platform_driver_unregister(&nct6775_driver);
4283}
4284
4285MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeck8aefb932014-11-16 09:50:04 -08004286MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004287MODULE_LICENSE("GPL");
4288
4289module_init(sensors_nct6775_init);
4290module_exit(sensors_nct6775_exit);