blob: 2aaedbe0b023529ba8524184640aac3acc36ea2f [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
Guenter Roeck728d2942015-08-31 16:13:47 -0700357/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
358#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
359#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
360
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700361static const s8 NCT6776_ALARM_BITS[] = {
362 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
363 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
364 -1, /* unused */
365 6, 7, 11, 10, 23, /* fan1..fan5 */
366 -1, -1, -1, /* unused */
367 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
368 12, 9 }; /* intrusion0, intrusion1 */
369
Guenter Roeck30846992013-06-24 22:21:59 -0700370static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
371
372static const s8 NCT6776_BEEP_BITS[] = {
373 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
374 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
375 24, /* global beep enable */
376 25, 26, 27, 28, 29, /* fan1..fan5 */
377 -1, -1, -1, /* unused */
378 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
379 30, 31 }; /* intrusion0, intrusion1 */
380
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800381static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700382 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800383
David Bartley578ab5f2013-06-24 22:28:28 -0700384static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
385static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800386
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800387static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800388static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800389
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800390static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700391 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800392
Guenter Roeckaa136e52012-12-04 03:26:05 -0800393static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
394 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
395
396static const char *const nct6776_temp_label[] = {
397 "",
398 "SYSTIN",
399 "CPUTIN",
400 "AUXTIN",
401 "SMBUSMASTER 0",
402 "SMBUSMASTER 1",
403 "SMBUSMASTER 2",
404 "SMBUSMASTER 3",
405 "SMBUSMASTER 4",
406 "SMBUSMASTER 5",
407 "SMBUSMASTER 6",
408 "SMBUSMASTER 7",
409 "PECI Agent 0",
410 "PECI Agent 1",
411 "PCH_CHIP_CPU_MAX_TEMP",
412 "PCH_CHIP_TEMP",
413 "PCH_CPU_TEMP",
414 "PCH_MCH_TEMP",
415 "PCH_DIM0_TEMP",
416 "PCH_DIM1_TEMP",
417 "PCH_DIM2_TEMP",
418 "PCH_DIM3_TEMP",
419 "BYTE_TEMP"
420};
421
422static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
423 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
424
425static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
426 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
427
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700428/* NCT6779 specific data */
429
430static const u16 NCT6779_REG_IN[] = {
431 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
432 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
433
434static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
435 0x459, 0x45A, 0x45B, 0x568 };
436
437static const s8 NCT6779_ALARM_BITS[] = {
438 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
439 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
440 -1, /* unused */
441 6, 7, 11, 10, 23, /* fan1..fan5 */
442 -1, -1, -1, /* unused */
443 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
444 12, 9 }; /* intrusion0, intrusion1 */
445
Guenter Roeck30846992013-06-24 22:21:59 -0700446static const s8 NCT6779_BEEP_BITS[] = {
447 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
448 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
449 24, /* global beep enable */
450 25, 26, 27, 28, 29, /* fan1..fan5 */
451 -1, -1, -1, /* unused */
452 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
453 30, 31 }; /* intrusion0, intrusion1 */
454
David Bartley578ab5f2013-06-24 22:28:28 -0700455static const u16 NCT6779_REG_FAN[] = {
456 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800457static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700458 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800459
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800460static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700461 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700462#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800463static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700464 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800465
Guenter Roeckaa136e52012-12-04 03:26:05 -0800466static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800467static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800468static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
469 0x18, 0x152 };
470static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
471 0x3a, 0x153 };
472static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
473 0x39, 0x155 };
474
475static const u16 NCT6779_REG_TEMP_OFFSET[] = {
476 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
477
478static const char *const nct6779_temp_label[] = {
479 "",
480 "SYSTIN",
481 "CPUTIN",
482 "AUXTIN0",
483 "AUXTIN1",
484 "AUXTIN2",
485 "AUXTIN3",
486 "",
487 "SMBUSMASTER 0",
488 "SMBUSMASTER 1",
489 "SMBUSMASTER 2",
490 "SMBUSMASTER 3",
491 "SMBUSMASTER 4",
492 "SMBUSMASTER 5",
493 "SMBUSMASTER 6",
494 "SMBUSMASTER 7",
495 "PECI Agent 0",
496 "PECI Agent 1",
497 "PCH_CHIP_CPU_MAX_TEMP",
498 "PCH_CHIP_TEMP",
499 "PCH_CPU_TEMP",
500 "PCH_MCH_TEMP",
501 "PCH_DIM0_TEMP",
502 "PCH_DIM1_TEMP",
503 "PCH_DIM2_TEMP",
504 "PCH_DIM3_TEMP",
505 "BYTE_TEMP"
506};
507
508static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
509 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
510 0, 0, 0, 0, 0, 0, 0, 0,
511 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
512 0x408, 0 };
513
514static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
515 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
516
David Bartley578ab5f2013-06-24 22:28:28 -0700517/* NCT6791 specific data */
518
519#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
520
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800521static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
522static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
523static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
524static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
525static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
526static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
527
David Bartley578ab5f2013-06-24 22:28:28 -0700528static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
529 0x459, 0x45A, 0x45B, 0x568, 0x45D };
530
531static const s8 NCT6791_ALARM_BITS[] = {
532 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
533 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
534 -1, /* unused */
535 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
536 -1, -1, /* unused */
537 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
538 12, 9 }; /* intrusion0, intrusion1 */
539
Guenter Roeck8aefb932014-11-16 09:50:04 -0800540/* NCT6792 specific data */
541
542static const u16 NCT6792_REG_TEMP_MON[] = {
543 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
544static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
545 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700546
Guenter Roeck6c009502012-07-01 08:23:15 -0700547/* NCT6102D/NCT6106D specific data */
548
549#define NCT6106_REG_VBAT 0x318
550#define NCT6106_REG_DIODE 0x319
551#define NCT6106_DIODE_MASK 0x01
552
553static const u16 NCT6106_REG_IN_MAX[] = {
554 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
555static const u16 NCT6106_REG_IN_MIN[] = {
556 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
557static const u16 NCT6106_REG_IN[] = {
558 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
559
560static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800561static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700562static const u16 NCT6106_REG_TEMP_HYST[] = {
563 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
564static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700565 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
566static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
567 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
568static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
569 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700570static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
571static const u16 NCT6106_REG_TEMP_CONFIG[] = {
572 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
573
574static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
575static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
576static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
577static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
578
579static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
580static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
581static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
582static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
583static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
584static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
585static const u16 NCT6106_REG_TEMP_SOURCE[] = {
586 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
587
588static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
589static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
590 0x11b, 0x12b, 0x13b };
591
592static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
593#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
594static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
595
596static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
597static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
598static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
599static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
600static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
601static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
602
603static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
604
605static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
606static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
607static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
608static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
609static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
610static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
611
612static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
613static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
614
615static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
616 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
617
618static const s8 NCT6106_ALARM_BITS[] = {
619 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
620 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
621 -1, /* unused */
622 32, 33, 34, -1, -1, /* fan1..fan5 */
623 -1, -1, -1, /* unused */
624 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
625 48, -1 /* intrusion0, intrusion1 */
626};
627
Guenter Roeck30846992013-06-24 22:21:59 -0700628static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
629 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
630
631static const s8 NCT6106_BEEP_BITS[] = {
632 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
633 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
634 32, /* global beep enable */
635 24, 25, 26, 27, 28, /* fan1..fan5 */
636 -1, -1, -1, /* unused */
637 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
638 34, -1 /* intrusion0, intrusion1 */
639};
640
Guenter Roeck6c009502012-07-01 08:23:15 -0700641static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
642 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
643
644static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
645 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
646
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800647static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
648{
649 if (mode == 0 && pwm == 255)
650 return off;
651 return mode + 1;
652}
653
654static int pwm_enable_to_reg(enum pwm_enable mode)
655{
656 if (mode == off)
657 return 0;
658 return mode - 1;
659}
660
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700661/*
662 * Conversions
663 */
664
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800665/* 1 is DC mode, output in ms */
666static unsigned int step_time_from_reg(u8 reg, u8 mode)
667{
668 return mode ? 400 * reg : 100 * reg;
669}
670
671static u8 step_time_to_reg(unsigned int msec, u8 mode)
672{
673 return clamp_val((mode ? (msec + 200) / 400 :
674 (msec + 50) / 100), 1, 255);
675}
676
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800677static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
678{
679 if (reg == 0 || reg == 255)
680 return 0;
681 return 1350000U / (reg << divreg);
682}
683
684static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
685{
686 if ((reg & 0xff1f) == 0xff1f)
687 return 0;
688
689 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
690
691 if (reg == 0)
692 return 0;
693
694 return 1350000U / reg;
695}
696
697static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
698{
699 if (reg == 0 || reg == 0xffff)
700 return 0;
701
702 /*
703 * Even though the registers are 16 bit wide, the fan divisor
704 * still applies.
705 */
706 return 1350000U / (reg << divreg);
707}
708
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800709static u16 fan_to_reg(u32 fan, unsigned int divreg)
710{
711 if (!fan)
712 return 0;
713
714 return (1350000U / fan) >> divreg;
715}
716
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800717static inline unsigned int
718div_from_reg(u8 reg)
719{
720 return 1 << reg;
721}
722
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700723/*
724 * Some of the voltage inputs have internal scaling, the tables below
725 * contain 8 (the ADC LSB in mV) * scaling factor * 100
726 */
727static const u16 scale_in[15] = {
728 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
729 800, 800
730};
731
732static inline long in_from_reg(u8 reg, u8 nr)
733{
734 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
735}
736
737static inline u8 in_to_reg(u32 val, u8 nr)
738{
739 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
740}
741
742/*
743 * Data structures and manipulation thereof
744 */
745
746struct nct6775_data {
747 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700748 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700749 enum kinds kind;
750 const char *name;
751
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700752 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700753
Guenter Roeckb7a61352013-04-02 22:14:06 -0700754 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
755 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800756 */
757 u8 temp_src[NUM_TEMP];
758 u16 reg_temp_config[NUM_TEMP];
759 const char * const *temp_label;
760 int temp_label_num;
761
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700762 u16 REG_CONFIG;
763 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800764 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700765 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700766
767 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700768 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700769
770 const u16 *REG_VIN;
771 const u16 *REG_IN_MINMAX[2];
772
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800773 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800774 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800775 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800776 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800777 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700778 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800779 const u16 *REG_FAN_TIME[3];
780
781 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800782
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800783 const u8 *REG_PWM_MODE;
784 const u8 *PWM_MODE_MASK;
785
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800786 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
787 * [3]=pwm_max, [4]=pwm_step,
788 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800789 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800790 const u16 *REG_PWM_READ;
791
Guenter Roeck6c009502012-07-01 08:23:15 -0700792 const u16 *REG_CRITICAL_PWM_ENABLE;
793 u8 CRITICAL_PWM_ENABLE_MASK;
794 const u16 *REG_CRITICAL_PWM;
795
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800796 const u16 *REG_AUTO_TEMP;
797 const u16 *REG_AUTO_PWM;
798
799 const u16 *REG_CRITICAL_TEMP;
800 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
801
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800802 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800803 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800804 const u16 *REG_WEIGHT_TEMP_SEL;
805 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
806
Guenter Roeckaa136e52012-12-04 03:26:05 -0800807 const u16 *REG_TEMP_OFFSET;
808
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700809 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700810 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700811
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800812 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
813 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
814
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700815 struct mutex update_lock;
816 bool valid; /* true if following fields are valid */
817 unsigned long last_updated; /* In jiffies */
818
819 /* Register values */
820 u8 bank; /* current register bank */
821 u8 in_num; /* number of in inputs we have */
822 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700823 unsigned int rpm[NUM_FAN];
824 u16 fan_min[NUM_FAN];
825 u8 fan_pulses[NUM_FAN];
826 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800827 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800828 u8 has_fan; /* some fan inputs can be disabled */
829 u8 has_fan_min; /* some fans don't have min register */
830 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700831
Guenter Roeck6c009502012-07-01 08:23:15 -0700832 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700833 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800834 u8 temp_fixed_num; /* 3 or 6 */
835 u8 temp_type[NUM_TEMP_FIXED];
836 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300837 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
838 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700839 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700840 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700841
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800842 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700843 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
844 * 0->PWM variable duty cycle
845 */
846 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800847 /* 0->off
848 * 1->manual
849 * 2->thermal cruise mode (also called SmartFan I)
850 * 3->fan speed cruise mode
851 * 4->SmartFan III
852 * 5->enhanced variable thermal cruise (SmartFan IV)
853 */
David Bartley578ab5f2013-06-24 22:28:28 -0700854 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
855 * [3]=pwm_max, [4]=pwm_step,
856 * [5]=weight_duty_step, [6]=weight_duty_base
857 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800858
David Bartley578ab5f2013-06-24 22:28:28 -0700859 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800860 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700861 u32 target_speed[NUM_FAN];
862 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800863 u8 speed_tolerance_limit;
864
David Bartley578ab5f2013-06-24 22:28:28 -0700865 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800866 u8 tolerance_mask;
867
David Bartley578ab5f2013-06-24 22:28:28 -0700868 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800869
870 /* Automatic fan speed control registers */
871 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700872 u8 auto_pwm[NUM_FAN][7];
873 u8 auto_temp[NUM_FAN][7];
874 u8 pwm_temp_sel[NUM_FAN];
875 u8 pwm_weight_temp_sel[NUM_FAN];
876 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
877 * 2->temp_base
878 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800879
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700880 u8 vid;
881 u8 vrm;
882
Guenter Roeckf73cf632013-03-18 09:22:50 -0700883 bool have_vid;
884
Guenter Roeckaa136e52012-12-04 03:26:05 -0800885 u16 have_temp;
886 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700887 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800888
Guenter Roeck84d19d92012-12-04 08:01:39 -0800889 /* Remember extra register values over suspend/resume */
890 u8 vbat;
891 u8 fandiv1;
892 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800893 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700894};
895
896struct nct6775_sio_data {
897 int sioreg;
898 enum kinds kind;
899};
900
Guenter Roeckf73cf632013-03-18 09:22:50 -0700901struct sensor_device_template {
902 struct device_attribute dev_attr;
903 union {
904 struct {
905 u8 nr;
906 u8 index;
907 } s;
908 int index;
909 } u;
910 bool s2; /* true if both index and nr are used */
911};
912
913struct sensor_device_attr_u {
914 union {
915 struct sensor_device_attribute a1;
916 struct sensor_device_attribute_2 a2;
917 } u;
918 char name[32];
919};
920
921#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
922 .attr = {.name = _template, .mode = _mode }, \
923 .show = _show, \
924 .store = _store, \
925}
926
927#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
928 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
929 .u.index = _index, \
930 .s2 = false }
931
932#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
933 _nr, _index) \
934 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
935 .u.s.index = _index, \
936 .u.s.nr = _nr, \
937 .s2 = true }
938
939#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
940static struct sensor_device_template sensor_dev_template_##_name \
941 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
942 _index)
943
944#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
945 _nr, _index) \
946static struct sensor_device_template sensor_dev_template_##_name \
947 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
948 _nr, _index)
949
950struct sensor_template_group {
951 struct sensor_device_template **templates;
952 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
953 int base;
954};
955
956static struct attribute_group *
957nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
958 int repeat)
959{
960 struct attribute_group *group;
961 struct sensor_device_attr_u *su;
962 struct sensor_device_attribute *a;
963 struct sensor_device_attribute_2 *a2;
964 struct attribute **attrs;
965 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300966 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700967
968 if (repeat <= 0)
969 return ERR_PTR(-EINVAL);
970
971 t = tg->templates;
972 for (count = 0; *t; t++, count++)
973 ;
974
975 if (count == 0)
976 return ERR_PTR(-EINVAL);
977
978 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
979 if (group == NULL)
980 return ERR_PTR(-ENOMEM);
981
982 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
983 GFP_KERNEL);
984 if (attrs == NULL)
985 return ERR_PTR(-ENOMEM);
986
987 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
988 GFP_KERNEL);
989 if (su == NULL)
990 return ERR_PTR(-ENOMEM);
991
992 group->attrs = attrs;
993 group->is_visible = tg->is_visible;
994
995 for (i = 0; i < repeat; i++) {
996 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300997 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -0700998 snprintf(su->name, sizeof(su->name),
999 (*t)->dev_attr.attr.name, tg->base + i);
1000 if ((*t)->s2) {
1001 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001002 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001003 a2->dev_attr.attr.name = su->name;
1004 a2->nr = (*t)->u.s.nr + i;
1005 a2->index = (*t)->u.s.index;
1006 a2->dev_attr.attr.mode =
1007 (*t)->dev_attr.attr.mode;
1008 a2->dev_attr.show = (*t)->dev_attr.show;
1009 a2->dev_attr.store = (*t)->dev_attr.store;
1010 *attrs = &a2->dev_attr.attr;
1011 } else {
1012 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001013 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001014 a->dev_attr.attr.name = su->name;
1015 a->index = (*t)->u.index + i;
1016 a->dev_attr.attr.mode =
1017 (*t)->dev_attr.attr.mode;
1018 a->dev_attr.show = (*t)->dev_attr.show;
1019 a->dev_attr.store = (*t)->dev_attr.store;
1020 *attrs = &a->dev_attr.attr;
1021 }
1022 attrs++;
1023 su++;
1024 t++;
1025 }
1026 }
1027
Guenter Roeckf73cf632013-03-18 09:22:50 -07001028 return group;
1029}
1030
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001031static bool is_word_sized(struct nct6775_data *data, u16 reg)
1032{
1033 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001034 case nct6106:
1035 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1036 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1037 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001038 case nct6775:
1039 return (((reg & 0xff00) == 0x100 ||
1040 (reg & 0xff00) == 0x200) &&
1041 ((reg & 0x00ff) == 0x50 ||
1042 (reg & 0x00ff) == 0x53 ||
1043 (reg & 0x00ff) == 0x55)) ||
1044 (reg & 0xfff0) == 0x630 ||
1045 reg == 0x640 || reg == 0x642 ||
1046 reg == 0x662 ||
1047 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1048 reg == 0x73 || reg == 0x75 || reg == 0x77;
1049 case nct6776:
1050 return (((reg & 0xff00) == 0x100 ||
1051 (reg & 0xff00) == 0x200) &&
1052 ((reg & 0x00ff) == 0x50 ||
1053 (reg & 0x00ff) == 0x53 ||
1054 (reg & 0x00ff) == 0x55)) ||
1055 (reg & 0xfff0) == 0x630 ||
1056 reg == 0x402 ||
1057 reg == 0x640 || reg == 0x642 ||
1058 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1059 reg == 0x73 || reg == 0x75 || reg == 0x77;
1060 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001061 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001062 case nct6792:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001063 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001064 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001065 reg == 0x402 ||
1066 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1067 reg == 0x640 || reg == 0x642 ||
1068 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001069 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001070 }
1071 return false;
1072}
1073
1074/*
1075 * On older chips, only registers 0x50-0x5f are banked.
1076 * On more recent chips, all registers are banked.
1077 * Assume that is the case and set the bank number for each access.
1078 * Cache the bank number so it only needs to be set if it changes.
1079 */
1080static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1081{
1082 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001083
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001084 if (data->bank != bank) {
1085 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1086 outb_p(bank, data->addr + DATA_REG_OFFSET);
1087 data->bank = bank;
1088 }
1089}
1090
1091static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1092{
1093 int res, word_sized = is_word_sized(data, reg);
1094
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001095 nct6775_set_bank(data, reg);
1096 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1097 res = inb_p(data->addr + DATA_REG_OFFSET);
1098 if (word_sized) {
1099 outb_p((reg & 0xff) + 1,
1100 data->addr + ADDR_REG_OFFSET);
1101 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1102 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001103 return res;
1104}
1105
1106static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1107{
1108 int word_sized = is_word_sized(data, reg);
1109
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001110 nct6775_set_bank(data, reg);
1111 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1112 if (word_sized) {
1113 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1114 outb_p((reg & 0xff) + 1,
1115 data->addr + ADDR_REG_OFFSET);
1116 }
1117 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001118 return 0;
1119}
1120
Guenter Roeckaa136e52012-12-04 03:26:05 -08001121/* We left-align 8-bit temperature values to make the code simpler */
1122static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1123{
1124 u16 res;
1125
1126 res = nct6775_read_value(data, reg);
1127 if (!is_word_sized(data, reg))
1128 res <<= 8;
1129
1130 return res;
1131}
1132
1133static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1134{
1135 if (!is_word_sized(data, reg))
1136 value >>= 8;
1137 return nct6775_write_value(data, reg, value);
1138}
1139
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001140/* This function assumes that the caller holds data->update_lock */
1141static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1142{
1143 u8 reg;
1144
1145 switch (nr) {
1146 case 0:
1147 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1148 | (data->fan_div[0] & 0x7);
1149 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1150 break;
1151 case 1:
1152 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1153 | ((data->fan_div[1] << 4) & 0x70);
1154 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1155 break;
1156 case 2:
1157 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1158 | (data->fan_div[2] & 0x7);
1159 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1160 break;
1161 case 3:
1162 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1163 | ((data->fan_div[3] << 4) & 0x70);
1164 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1165 break;
1166 }
1167}
1168
1169static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1170{
1171 if (data->kind == nct6775)
1172 nct6775_write_fan_div(data, nr);
1173}
1174
1175static void nct6775_update_fan_div(struct nct6775_data *data)
1176{
1177 u8 i;
1178
1179 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1180 data->fan_div[0] = i & 0x7;
1181 data->fan_div[1] = (i & 0x70) >> 4;
1182 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1183 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001184 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001185 data->fan_div[3] = (i & 0x70) >> 4;
1186}
1187
1188static void nct6775_update_fan_div_common(struct nct6775_data *data)
1189{
1190 if (data->kind == nct6775)
1191 nct6775_update_fan_div(data);
1192}
1193
1194static void nct6775_init_fan_div(struct nct6775_data *data)
1195{
1196 int i;
1197
1198 nct6775_update_fan_div_common(data);
1199 /*
1200 * For all fans, start with highest divider value if the divider
1201 * register is not initialized. This ensures that we get a
1202 * reading from the fan count register, even if it is not optimal.
1203 * We'll compute a better divider later on.
1204 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001205 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001206 if (!(data->has_fan & (1 << i)))
1207 continue;
1208 if (data->fan_div[i] == 0) {
1209 data->fan_div[i] = 7;
1210 nct6775_write_fan_div_common(data, i);
1211 }
1212 }
1213}
1214
1215static void nct6775_init_fan_common(struct device *dev,
1216 struct nct6775_data *data)
1217{
1218 int i;
1219 u8 reg;
1220
1221 if (data->has_fan_div)
1222 nct6775_init_fan_div(data);
1223
1224 /*
1225 * If fan_min is not set (0), set it to 0xff to disable it. This
1226 * prevents the unnecessary warning when fanX_min is reported as 0.
1227 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001228 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001229 if (data->has_fan_min & (1 << i)) {
1230 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1231 if (!reg)
1232 nct6775_write_value(data, data->REG_FAN_MIN[i],
1233 data->has_fan_div ? 0xff
1234 : 0xff1f);
1235 }
1236 }
1237}
1238
1239static void nct6775_select_fan_div(struct device *dev,
1240 struct nct6775_data *data, int nr, u16 reg)
1241{
1242 u8 fan_div = data->fan_div[nr];
1243 u16 fan_min;
1244
1245 if (!data->has_fan_div)
1246 return;
1247
1248 /*
1249 * If we failed to measure the fan speed, or the reported value is not
1250 * in the optimal range, and the clock divider can be modified,
1251 * let's try that for next time.
1252 */
1253 if (reg == 0x00 && fan_div < 0x07)
1254 fan_div++;
1255 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1256 fan_div--;
1257
1258 if (fan_div != data->fan_div[nr]) {
1259 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1260 nr + 1, div_from_reg(data->fan_div[nr]),
1261 div_from_reg(fan_div));
1262
1263 /* Preserve min limit if possible */
1264 if (data->has_fan_min & (1 << nr)) {
1265 fan_min = data->fan_min[nr];
1266 if (fan_div > data->fan_div[nr]) {
1267 if (fan_min != 255 && fan_min > 1)
1268 fan_min >>= 1;
1269 } else {
1270 if (fan_min != 255) {
1271 fan_min <<= 1;
1272 if (fan_min > 254)
1273 fan_min = 254;
1274 }
1275 }
1276 if (fan_min != data->fan_min[nr]) {
1277 data->fan_min[nr] = fan_min;
1278 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1279 fan_min);
1280 }
1281 }
1282 data->fan_div[nr] = fan_div;
1283 nct6775_write_fan_div_common(data, nr);
1284 }
1285}
1286
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001287static void nct6775_update_pwm(struct device *dev)
1288{
1289 struct nct6775_data *data = dev_get_drvdata(dev);
1290 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001291 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001292 bool duty_is_dc;
1293
1294 for (i = 0; i < data->pwm_num; i++) {
1295 if (!(data->has_pwm & (1 << i)))
1296 continue;
1297
1298 duty_is_dc = data->REG_PWM_MODE[i] &&
1299 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1300 & data->PWM_MODE_MASK[i]);
1301 data->pwm_mode[i] = duty_is_dc;
1302
1303 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1304 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1305 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1306 data->pwm[j][i]
1307 = nct6775_read_value(data,
1308 data->REG_PWM[j][i]);
1309 }
1310 }
1311
1312 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1313 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001314
1315 if (!data->temp_tolerance[0][i] ||
1316 data->pwm_enable[i] != speed_cruise)
1317 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1318 if (!data->target_speed_tolerance[i] ||
1319 data->pwm_enable[i] == speed_cruise) {
1320 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001321
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001322 if (data->REG_TOLERANCE_H) {
1323 t |= (nct6775_read_value(data,
1324 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1325 }
1326 data->target_speed_tolerance[i] = t;
1327 }
1328
1329 data->temp_tolerance[1][i] =
1330 nct6775_read_value(data,
1331 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1332
1333 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1334 data->pwm_temp_sel[i] = reg & 0x1f;
1335 /* If fan can stop, report floor as 0 */
1336 if (reg & 0x80)
1337 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001338
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001339 if (!data->REG_WEIGHT_TEMP_SEL[i])
1340 continue;
1341
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001342 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1343 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1344 /* If weight is disabled, report weight source as 0 */
1345 if (j == 1 && !(reg & 0x80))
1346 data->pwm_weight_temp_sel[i] = 0;
1347
1348 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001349 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001350 data->weight_temp[j][i]
1351 = nct6775_read_value(data,
1352 data->REG_WEIGHT_TEMP[j][i]);
1353 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001354 }
1355}
1356
1357static void nct6775_update_pwm_limits(struct device *dev)
1358{
1359 struct nct6775_data *data = dev_get_drvdata(dev);
1360 int i, j;
1361 u8 reg;
1362 u16 reg_t;
1363
1364 for (i = 0; i < data->pwm_num; i++) {
1365 if (!(data->has_pwm & (1 << i)))
1366 continue;
1367
Guenter Roeckc409fd42013-04-09 05:04:00 -07001368 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001369 data->fan_time[j][i] =
1370 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1371 }
1372
1373 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1374 /* Update only in matching mode or if never updated */
1375 if (!data->target_temp[i] ||
1376 data->pwm_enable[i] == thermal_cruise)
1377 data->target_temp[i] = reg_t & data->target_temp_mask;
1378 if (!data->target_speed[i] ||
1379 data->pwm_enable[i] == speed_cruise) {
1380 if (data->REG_TOLERANCE_H) {
1381 reg_t |= (nct6775_read_value(data,
1382 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1383 }
1384 data->target_speed[i] = reg_t;
1385 }
1386
1387 for (j = 0; j < data->auto_pwm_num; j++) {
1388 data->auto_pwm[i][j] =
1389 nct6775_read_value(data,
1390 NCT6775_AUTO_PWM(data, i, j));
1391 data->auto_temp[i][j] =
1392 nct6775_read_value(data,
1393 NCT6775_AUTO_TEMP(data, i, j));
1394 }
1395
1396 /* critical auto_pwm temperature data */
1397 data->auto_temp[i][data->auto_pwm_num] =
1398 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1399
1400 switch (data->kind) {
1401 case nct6775:
1402 reg = nct6775_read_value(data,
1403 NCT6775_REG_CRITICAL_ENAB[i]);
1404 data->auto_pwm[i][data->auto_pwm_num] =
1405 (reg & 0x02) ? 0xff : 0x00;
1406 break;
1407 case nct6776:
1408 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1409 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001410 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001411 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001412 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001413 case nct6792:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001414 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001415 data->REG_CRITICAL_PWM_ENABLE[i]);
1416 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1417 reg = nct6775_read_value(data,
1418 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001419 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001420 reg = 0xff;
1421 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001422 break;
1423 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001424 }
1425}
1426
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001427static struct nct6775_data *nct6775_update_device(struct device *dev)
1428{
1429 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001430 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001431
1432 mutex_lock(&data->update_lock);
1433
Guenter Roeck6445e662013-04-21 09:13:28 -07001434 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001435 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001436 /* Fan clock dividers */
1437 nct6775_update_fan_div_common(data);
1438
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001439 /* Measured voltages and limits */
1440 for (i = 0; i < data->in_num; i++) {
1441 if (!(data->have_in & (1 << i)))
1442 continue;
1443
1444 data->in[i][0] = nct6775_read_value(data,
1445 data->REG_VIN[i]);
1446 data->in[i][1] = nct6775_read_value(data,
1447 data->REG_IN_MINMAX[0][i]);
1448 data->in[i][2] = nct6775_read_value(data,
1449 data->REG_IN_MINMAX[1][i]);
1450 }
1451
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001452 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001453 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001454 u16 reg;
1455
1456 if (!(data->has_fan & (1 << i)))
1457 continue;
1458
1459 reg = nct6775_read_value(data, data->REG_FAN[i]);
1460 data->rpm[i] = data->fan_from_reg(reg,
1461 data->fan_div[i]);
1462
1463 if (data->has_fan_min & (1 << i))
1464 data->fan_min[i] = nct6775_read_value(data,
1465 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001466 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001467 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1468 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001469
1470 nct6775_select_fan_div(dev, data, i, reg);
1471 }
1472
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001473 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001474 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001475
Guenter Roeckaa136e52012-12-04 03:26:05 -08001476 /* Measured temperatures and limits */
1477 for (i = 0; i < NUM_TEMP; i++) {
1478 if (!(data->have_temp & (1 << i)))
1479 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001480 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001481 if (data->reg_temp[j][i])
1482 data->temp[j][i]
1483 = nct6775_read_temp(data,
1484 data->reg_temp[j][i]);
1485 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001486 if (i >= NUM_TEMP_FIXED ||
1487 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001488 continue;
1489 data->temp_offset[i]
1490 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1491 }
1492
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001493 data->alarms = 0;
1494 for (i = 0; i < NUM_REG_ALARM; i++) {
1495 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001496
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001497 if (!data->REG_ALARM[i])
1498 continue;
1499 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1500 data->alarms |= ((u64)alarm) << (i << 3);
1501 }
1502
Guenter Roeck30846992013-06-24 22:21:59 -07001503 data->beeps = 0;
1504 for (i = 0; i < NUM_REG_BEEP; i++) {
1505 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001506
Guenter Roeck30846992013-06-24 22:21:59 -07001507 if (!data->REG_BEEP[i])
1508 continue;
1509 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1510 data->beeps |= ((u64)beep) << (i << 3);
1511 }
1512
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001513 data->last_updated = jiffies;
1514 data->valid = true;
1515 }
1516
1517 mutex_unlock(&data->update_lock);
1518 return data;
1519}
1520
1521/*
1522 * Sysfs callback functions
1523 */
1524static ssize_t
1525show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1526{
1527 struct nct6775_data *data = nct6775_update_device(dev);
1528 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001529 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001530 int nr = sattr->nr;
1531
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001532 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1533}
1534
1535static ssize_t
1536store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1537 size_t count)
1538{
1539 struct nct6775_data *data = dev_get_drvdata(dev);
1540 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001541 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001542 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001543 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001544 int err;
1545
1546 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001547 if (err < 0)
1548 return err;
1549 mutex_lock(&data->update_lock);
1550 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001551 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001552 data->in[nr][index]);
1553 mutex_unlock(&data->update_lock);
1554 return count;
1555}
1556
1557static ssize_t
1558show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1559{
1560 struct nct6775_data *data = nct6775_update_device(dev);
1561 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1562 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001563
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001564 return sprintf(buf, "%u\n",
1565 (unsigned int)((data->alarms >> nr) & 0x01));
1566}
1567
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001568static int find_temp_source(struct nct6775_data *data, int index, int count)
1569{
1570 int source = data->temp_src[index];
1571 int nr;
1572
1573 for (nr = 0; nr < count; nr++) {
1574 int src;
1575
1576 src = nct6775_read_value(data,
1577 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1578 if (src == source)
1579 return nr;
1580 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001581 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001582}
1583
1584static ssize_t
1585show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1586{
1587 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1588 struct nct6775_data *data = nct6775_update_device(dev);
1589 unsigned int alarm = 0;
1590 int nr;
1591
1592 /*
1593 * For temperatures, there is no fixed mapping from registers to alarm
1594 * bits. Alarm bits are determined by the temperature source mapping.
1595 */
1596 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1597 if (nr >= 0) {
1598 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001599
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001600 alarm = (data->alarms >> bit) & 0x01;
1601 }
1602 return sprintf(buf, "%u\n", alarm);
1603}
1604
Guenter Roeck30846992013-06-24 22:21:59 -07001605static ssize_t
1606show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1607{
1608 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1609 struct nct6775_data *data = nct6775_update_device(dev);
1610 int nr = data->BEEP_BITS[sattr->index];
1611
1612 return sprintf(buf, "%u\n",
1613 (unsigned int)((data->beeps >> nr) & 0x01));
1614}
1615
1616static ssize_t
1617store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1618 size_t count)
1619{
1620 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1621 struct nct6775_data *data = dev_get_drvdata(dev);
1622 int nr = data->BEEP_BITS[sattr->index];
1623 int regindex = nr >> 3;
1624 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001625 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001626
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001627 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001628 if (err < 0)
1629 return err;
1630 if (val > 1)
1631 return -EINVAL;
1632
1633 mutex_lock(&data->update_lock);
1634 if (val)
1635 data->beeps |= (1ULL << nr);
1636 else
1637 data->beeps &= ~(1ULL << nr);
1638 nct6775_write_value(data, data->REG_BEEP[regindex],
1639 (data->beeps >> (regindex << 3)) & 0xff);
1640 mutex_unlock(&data->update_lock);
1641 return count;
1642}
1643
1644static ssize_t
1645show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1646{
1647 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1648 struct nct6775_data *data = nct6775_update_device(dev);
1649 unsigned int beep = 0;
1650 int nr;
1651
1652 /*
1653 * For temperatures, there is no fixed mapping from registers to beep
1654 * enable bits. Beep enable bits are determined by the temperature
1655 * source mapping.
1656 */
1657 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1658 if (nr >= 0) {
1659 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001660
Guenter Roeck30846992013-06-24 22:21:59 -07001661 beep = (data->beeps >> bit) & 0x01;
1662 }
1663 return sprintf(buf, "%u\n", beep);
1664}
1665
1666static ssize_t
1667store_temp_beep(struct device *dev, struct device_attribute *attr,
1668 const char *buf, size_t count)
1669{
1670 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1671 struct nct6775_data *data = dev_get_drvdata(dev);
1672 int nr, bit, regindex;
1673 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001674 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001675
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001676 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001677 if (err < 0)
1678 return err;
1679 if (val > 1)
1680 return -EINVAL;
1681
1682 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1683 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001684 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001685
1686 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1687 regindex = bit >> 3;
1688
1689 mutex_lock(&data->update_lock);
1690 if (val)
1691 data->beeps |= (1ULL << bit);
1692 else
1693 data->beeps &= ~(1ULL << bit);
1694 nct6775_write_value(data, data->REG_BEEP[regindex],
1695 (data->beeps >> (regindex << 3)) & 0xff);
1696 mutex_unlock(&data->update_lock);
1697
1698 return count;
1699}
1700
Guenter Roeckf73cf632013-03-18 09:22:50 -07001701static umode_t nct6775_in_is_visible(struct kobject *kobj,
1702 struct attribute *attr, int index)
1703{
1704 struct device *dev = container_of(kobj, struct device, kobj);
1705 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001706 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001707
Guenter Roeckf73cf632013-03-18 09:22:50 -07001708 if (!(data->have_in & (1 << in)))
1709 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001710
Guenter Roeckf73cf632013-03-18 09:22:50 -07001711 return attr->mode;
1712}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001713
Guenter Roeckf73cf632013-03-18 09:22:50 -07001714SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1715SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001716SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1717 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001718SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1719 store_in_reg, 0, 1);
1720SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1721 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001722
Guenter Roeckf73cf632013-03-18 09:22:50 -07001723/*
1724 * nct6775_in_is_visible uses the index into the following array
1725 * to determine if attributes should be created or not.
1726 * Any change in order or content must be matched.
1727 */
1728static struct sensor_device_template *nct6775_attributes_in_template[] = {
1729 &sensor_dev_template_in_input,
1730 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001731 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001732 &sensor_dev_template_in_min,
1733 &sensor_dev_template_in_max,
1734 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001735};
1736
Guenter Roeckf73cf632013-03-18 09:22:50 -07001737static struct sensor_template_group nct6775_in_template_group = {
1738 .templates = nct6775_attributes_in_template,
1739 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001740};
1741
1742static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001743show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1744{
1745 struct nct6775_data *data = nct6775_update_device(dev);
1746 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1747 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001748
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001749 return sprintf(buf, "%d\n", data->rpm[nr]);
1750}
1751
1752static ssize_t
1753show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1754{
1755 struct nct6775_data *data = nct6775_update_device(dev);
1756 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1757 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001758
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001759 return sprintf(buf, "%d\n",
1760 data->fan_from_reg_min(data->fan_min[nr],
1761 data->fan_div[nr]));
1762}
1763
1764static ssize_t
1765show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1766{
1767 struct nct6775_data *data = nct6775_update_device(dev);
1768 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1769 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001770
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001771 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1772}
1773
1774static ssize_t
1775store_fan_min(struct device *dev, struct device_attribute *attr,
1776 const char *buf, size_t count)
1777{
1778 struct nct6775_data *data = dev_get_drvdata(dev);
1779 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1780 int nr = sattr->index;
1781 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001782 unsigned int reg;
1783 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001784 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001785
1786 err = kstrtoul(buf, 10, &val);
1787 if (err < 0)
1788 return err;
1789
1790 mutex_lock(&data->update_lock);
1791 if (!data->has_fan_div) {
1792 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1793 if (!val) {
1794 val = 0xff1f;
1795 } else {
1796 if (val > 1350000U)
1797 val = 135000U;
1798 val = 1350000U / val;
1799 val = (val & 0x1f) | ((val << 3) & 0xff00);
1800 }
1801 data->fan_min[nr] = val;
1802 goto write_min; /* Leave fan divider alone */
1803 }
1804 if (!val) {
1805 /* No min limit, alarm disabled */
1806 data->fan_min[nr] = 255;
1807 new_div = data->fan_div[nr]; /* No change */
1808 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1809 goto write_div;
1810 }
1811 reg = 1350000U / val;
1812 if (reg >= 128 * 255) {
1813 /*
1814 * Speed below this value cannot possibly be represented,
1815 * even with the highest divider (128)
1816 */
1817 data->fan_min[nr] = 254;
1818 new_div = 7; /* 128 == (1 << 7) */
1819 dev_warn(dev,
1820 "fan%u low limit %lu below minimum %u, set to minimum\n",
1821 nr + 1, val, data->fan_from_reg_min(254, 7));
1822 } else if (!reg) {
1823 /*
1824 * Speed above this value cannot possibly be represented,
1825 * even with the lowest divider (1)
1826 */
1827 data->fan_min[nr] = 1;
1828 new_div = 0; /* 1 == (1 << 0) */
1829 dev_warn(dev,
1830 "fan%u low limit %lu above maximum %u, set to maximum\n",
1831 nr + 1, val, data->fan_from_reg_min(1, 0));
1832 } else {
1833 /*
1834 * Automatically pick the best divider, i.e. the one such
1835 * that the min limit will correspond to a register value
1836 * in the 96..192 range
1837 */
1838 new_div = 0;
1839 while (reg > 192 && new_div < 7) {
1840 reg >>= 1;
1841 new_div++;
1842 }
1843 data->fan_min[nr] = reg;
1844 }
1845
1846write_div:
1847 /*
1848 * Write both the fan clock divider (if it changed) and the new
1849 * fan min (unconditionally)
1850 */
1851 if (new_div != data->fan_div[nr]) {
1852 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1853 nr + 1, div_from_reg(data->fan_div[nr]),
1854 div_from_reg(new_div));
1855 data->fan_div[nr] = new_div;
1856 nct6775_write_fan_div_common(data, nr);
1857 /* Give the chip time to sample a new speed value */
1858 data->last_updated = jiffies;
1859 }
1860
1861write_min:
1862 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1863 mutex_unlock(&data->update_lock);
1864
1865 return count;
1866}
1867
Guenter Roeck5c25d952012-12-11 07:29:06 -08001868static ssize_t
1869show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1870{
1871 struct nct6775_data *data = nct6775_update_device(dev);
1872 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1873 int p = data->fan_pulses[sattr->index];
1874
1875 return sprintf(buf, "%d\n", p ? : 4);
1876}
1877
1878static ssize_t
1879store_fan_pulses(struct device *dev, struct device_attribute *attr,
1880 const char *buf, size_t count)
1881{
1882 struct nct6775_data *data = dev_get_drvdata(dev);
1883 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1884 int nr = sattr->index;
1885 unsigned long val;
1886 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001887 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001888
1889 err = kstrtoul(buf, 10, &val);
1890 if (err < 0)
1891 return err;
1892
1893 if (val > 4)
1894 return -EINVAL;
1895
1896 mutex_lock(&data->update_lock);
1897 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001898 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1899 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1900 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1901 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001902 mutex_unlock(&data->update_lock);
1903
1904 return count;
1905}
1906
Guenter Roeckf73cf632013-03-18 09:22:50 -07001907static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1908 struct attribute *attr, int index)
1909{
1910 struct device *dev = container_of(kobj, struct device, kobj);
1911 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001912 int fan = index / 6; /* fan index */
1913 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001914
1915 if (!(data->has_fan & (1 << fan)))
1916 return 0;
1917
1918 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1919 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001920 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001921 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001922 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1923 return 0;
1924 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001925 return 0;
1926
1927 return attr->mode;
1928}
1929
1930SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1931SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1932 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001933SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1934 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001935SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1936 store_fan_pulses, 0);
1937SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1938 store_fan_min, 0);
1939SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1940
1941/*
1942 * nct6775_fan_is_visible uses the index into the following array
1943 * to determine if attributes should be created or not.
1944 * Any change in order or content must be matched.
1945 */
1946static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1947 &sensor_dev_template_fan_input,
1948 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001949 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001950 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001951 &sensor_dev_template_fan_min, /* 4 */
1952 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001953 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001954};
1955
Guenter Roeckf73cf632013-03-18 09:22:50 -07001956static struct sensor_template_group nct6775_fan_template_group = {
1957 .templates = nct6775_attributes_fan_template,
1958 .is_visible = nct6775_fan_is_visible,
1959 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001960};
1961
1962static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001963show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1964{
1965 struct nct6775_data *data = nct6775_update_device(dev);
1966 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1967 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001968
Guenter Roeckaa136e52012-12-04 03:26:05 -08001969 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1970}
1971
1972static ssize_t
1973show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1974{
1975 struct nct6775_data *data = nct6775_update_device(dev);
1976 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1977 int nr = sattr->nr;
1978 int index = sattr->index;
1979
1980 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1981}
1982
1983static ssize_t
1984store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1985 size_t count)
1986{
1987 struct nct6775_data *data = dev_get_drvdata(dev);
1988 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1989 int nr = sattr->nr;
1990 int index = sattr->index;
1991 int err;
1992 long val;
1993
1994 err = kstrtol(buf, 10, &val);
1995 if (err < 0)
1996 return err;
1997
1998 mutex_lock(&data->update_lock);
1999 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2000 nct6775_write_temp(data, data->reg_temp[index][nr],
2001 data->temp[index][nr]);
2002 mutex_unlock(&data->update_lock);
2003 return count;
2004}
2005
2006static ssize_t
2007show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2008{
2009 struct nct6775_data *data = nct6775_update_device(dev);
2010 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2011
2012 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2013}
2014
2015static ssize_t
2016store_temp_offset(struct device *dev, struct device_attribute *attr,
2017 const char *buf, size_t count)
2018{
2019 struct nct6775_data *data = dev_get_drvdata(dev);
2020 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2021 int nr = sattr->index;
2022 long val;
2023 int err;
2024
2025 err = kstrtol(buf, 10, &val);
2026 if (err < 0)
2027 return err;
2028
2029 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2030
2031 mutex_lock(&data->update_lock);
2032 data->temp_offset[nr] = val;
2033 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2034 mutex_unlock(&data->update_lock);
2035
2036 return count;
2037}
2038
2039static ssize_t
2040show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2041{
2042 struct nct6775_data *data = nct6775_update_device(dev);
2043 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2044 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002045
Guenter Roeckaa136e52012-12-04 03:26:05 -08002046 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2047}
2048
2049static ssize_t
2050store_temp_type(struct device *dev, struct device_attribute *attr,
2051 const char *buf, size_t count)
2052{
2053 struct nct6775_data *data = nct6775_update_device(dev);
2054 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2055 int nr = sattr->index;
2056 unsigned long val;
2057 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002058 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002059
2060 err = kstrtoul(buf, 10, &val);
2061 if (err < 0)
2062 return err;
2063
2064 if (val != 1 && val != 3 && val != 4)
2065 return -EINVAL;
2066
2067 mutex_lock(&data->update_lock);
2068
2069 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002070 vbit = 0x02 << nr;
2071 dbit = data->DIODE_MASK << nr;
2072 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2073 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002074 switch (val) {
2075 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002076 vbat |= vbit;
2077 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002078 break;
2079 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002080 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002081 break;
2082 case 4: /* thermistor */
2083 break;
2084 }
2085 nct6775_write_value(data, data->REG_VBAT, vbat);
2086 nct6775_write_value(data, data->REG_DIODE, diode);
2087
2088 mutex_unlock(&data->update_lock);
2089 return count;
2090}
2091
Guenter Roeckf73cf632013-03-18 09:22:50 -07002092static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2093 struct attribute *attr, int index)
2094{
2095 struct device *dev = container_of(kobj, struct device, kobj);
2096 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002097 int temp = index / 10; /* temp index */
2098 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002099
2100 if (!(data->have_temp & (1 << temp)))
2101 return 0;
2102
2103 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2104 return 0; /* alarm */
2105
Guenter Roeck30846992013-06-24 22:21:59 -07002106 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2107 return 0; /* beep */
2108
2109 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002110 return 0;
2111
Guenter Roeck30846992013-06-24 22:21:59 -07002112 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002113 return 0;
2114
Guenter Roeck30846992013-06-24 22:21:59 -07002115 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002116 return 0;
2117
Guenter Roeck30846992013-06-24 22:21:59 -07002118 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002119 return 0;
2120
2121 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002122 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002123 return 0;
2124
2125 return attr->mode;
2126}
2127
2128SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2129SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2130SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2131 store_temp, 0, 1);
2132SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2133 show_temp, store_temp, 0, 2);
2134SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2135 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002136SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2137 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002138SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2139 show_temp_offset, store_temp_offset, 0);
2140SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2141 store_temp_type, 0);
2142SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002143SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2144 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002145
2146/*
2147 * nct6775_temp_is_visible uses the index into the following array
2148 * to determine if attributes should be created or not.
2149 * Any change in order or content must be matched.
2150 */
2151static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2152 &sensor_dev_template_temp_input,
2153 &sensor_dev_template_temp_label,
2154 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002155 &sensor_dev_template_temp_beep, /* 3 */
2156 &sensor_dev_template_temp_max, /* 4 */
2157 &sensor_dev_template_temp_max_hyst, /* 5 */
2158 &sensor_dev_template_temp_crit, /* 6 */
2159 &sensor_dev_template_temp_lcrit, /* 7 */
2160 &sensor_dev_template_temp_offset, /* 8 */
2161 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002162 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002163};
2164
Guenter Roeckf73cf632013-03-18 09:22:50 -07002165static struct sensor_template_group nct6775_temp_template_group = {
2166 .templates = nct6775_attributes_temp_template,
2167 .is_visible = nct6775_temp_is_visible,
2168 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002169};
2170
Guenter Roeckaa136e52012-12-04 03:26:05 -08002171static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002172show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2173{
2174 struct nct6775_data *data = nct6775_update_device(dev);
2175 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2176
2177 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2178}
2179
2180static ssize_t
2181store_pwm_mode(struct device *dev, struct device_attribute *attr,
2182 const char *buf, size_t count)
2183{
2184 struct nct6775_data *data = dev_get_drvdata(dev);
2185 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2186 int nr = sattr->index;
2187 unsigned long val;
2188 int err;
2189 u8 reg;
2190
2191 err = kstrtoul(buf, 10, &val);
2192 if (err < 0)
2193 return err;
2194
2195 if (val > 1)
2196 return -EINVAL;
2197
2198 /* Setting DC mode is not supported for all chips/channels */
2199 if (data->REG_PWM_MODE[nr] == 0) {
2200 if (val)
2201 return -EINVAL;
2202 return count;
2203 }
2204
2205 mutex_lock(&data->update_lock);
2206 data->pwm_mode[nr] = val;
2207 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2208 reg &= ~data->PWM_MODE_MASK[nr];
2209 if (val)
2210 reg |= data->PWM_MODE_MASK[nr];
2211 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2212 mutex_unlock(&data->update_lock);
2213 return count;
2214}
2215
2216static ssize_t
2217show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2218{
2219 struct nct6775_data *data = nct6775_update_device(dev);
2220 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2221 int nr = sattr->nr;
2222 int index = sattr->index;
2223 int pwm;
2224
2225 /*
2226 * For automatic fan control modes, show current pwm readings.
2227 * Otherwise, show the configured value.
2228 */
2229 if (index == 0 && data->pwm_enable[nr] > manual)
2230 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2231 else
2232 pwm = data->pwm[index][nr];
2233
2234 return sprintf(buf, "%d\n", pwm);
2235}
2236
2237static ssize_t
2238store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2239 size_t count)
2240{
2241 struct nct6775_data *data = dev_get_drvdata(dev);
2242 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2243 int nr = sattr->nr;
2244 int index = sattr->index;
2245 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002246 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2247 int maxval[7]
2248 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002249 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002250 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002251
2252 err = kstrtoul(buf, 10, &val);
2253 if (err < 0)
2254 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002255 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002256
2257 mutex_lock(&data->update_lock);
2258 data->pwm[index][nr] = val;
2259 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002260 if (index == 2) { /* floor: disable if val == 0 */
2261 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2262 reg &= 0x7f;
2263 if (val)
2264 reg |= 0x80;
2265 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2266 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002267 mutex_unlock(&data->update_lock);
2268 return count;
2269}
2270
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002271/* Returns 0 if OK, -EINVAL otherwise */
2272static int check_trip_points(struct nct6775_data *data, int nr)
2273{
2274 int i;
2275
2276 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2277 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2278 return -EINVAL;
2279 }
2280 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2281 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2282 return -EINVAL;
2283 }
2284 /* validate critical temperature and pwm if enabled (pwm > 0) */
2285 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2286 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2287 data->auto_temp[nr][data->auto_pwm_num] ||
2288 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2289 data->auto_pwm[nr][data->auto_pwm_num])
2290 return -EINVAL;
2291 }
2292 return 0;
2293}
2294
2295static void pwm_update_registers(struct nct6775_data *data, int nr)
2296{
2297 u8 reg;
2298
2299 switch (data->pwm_enable[nr]) {
2300 case off:
2301 case manual:
2302 break;
2303 case speed_cruise:
2304 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2305 reg = (reg & ~data->tolerance_mask) |
2306 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2307 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2308 nct6775_write_value(data, data->REG_TARGET[nr],
2309 data->target_speed[nr] & 0xff);
2310 if (data->REG_TOLERANCE_H) {
2311 reg = (data->target_speed[nr] >> 8) & 0x0f;
2312 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2313 nct6775_write_value(data,
2314 data->REG_TOLERANCE_H[nr],
2315 reg);
2316 }
2317 break;
2318 case thermal_cruise:
2319 nct6775_write_value(data, data->REG_TARGET[nr],
2320 data->target_temp[nr]);
2321 /* intentional */
2322 default:
2323 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2324 reg = (reg & ~data->tolerance_mask) |
2325 data->temp_tolerance[0][nr];
2326 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2327 break;
2328 }
2329}
2330
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002331static ssize_t
2332show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2333{
2334 struct nct6775_data *data = nct6775_update_device(dev);
2335 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2336
2337 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2338}
2339
2340static ssize_t
2341store_pwm_enable(struct device *dev, struct device_attribute *attr,
2342 const char *buf, size_t count)
2343{
2344 struct nct6775_data *data = dev_get_drvdata(dev);
2345 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2346 int nr = sattr->index;
2347 unsigned long val;
2348 int err;
2349 u16 reg;
2350
2351 err = kstrtoul(buf, 10, &val);
2352 if (err < 0)
2353 return err;
2354
2355 if (val > sf4)
2356 return -EINVAL;
2357
2358 if (val == sf3 && data->kind != nct6775)
2359 return -EINVAL;
2360
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002361 if (val == sf4 && check_trip_points(data, nr)) {
2362 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2363 dev_err(dev, "Adjust trip points and try again\n");
2364 return -EINVAL;
2365 }
2366
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002367 mutex_lock(&data->update_lock);
2368 data->pwm_enable[nr] = val;
2369 if (val == off) {
2370 /*
2371 * turn off pwm control: select manual mode, set pwm to maximum
2372 */
2373 data->pwm[0][nr] = 255;
2374 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2375 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002376 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002377 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2378 reg &= 0x0f;
2379 reg |= pwm_enable_to_reg(val) << 4;
2380 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2381 mutex_unlock(&data->update_lock);
2382 return count;
2383}
2384
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002385static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002386show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002387{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002388 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002389
2390 for (i = 0; i < NUM_TEMP; i++) {
2391 if (!(data->have_temp & (1 << i)))
2392 continue;
2393 if (src == data->temp_src[i]) {
2394 sel = i + 1;
2395 break;
2396 }
2397 }
2398
2399 return sprintf(buf, "%d\n", sel);
2400}
2401
2402static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002403show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2404{
2405 struct nct6775_data *data = nct6775_update_device(dev);
2406 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2407 int index = sattr->index;
2408
2409 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2410}
2411
2412static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002413store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2414 const char *buf, size_t count)
2415{
2416 struct nct6775_data *data = nct6775_update_device(dev);
2417 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2418 int nr = sattr->index;
2419 unsigned long val;
2420 int err, reg, src;
2421
2422 err = kstrtoul(buf, 10, &val);
2423 if (err < 0)
2424 return err;
2425 if (val == 0 || val > NUM_TEMP)
2426 return -EINVAL;
2427 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2428 return -EINVAL;
2429
2430 mutex_lock(&data->update_lock);
2431 src = data->temp_src[val - 1];
2432 data->pwm_temp_sel[nr] = src;
2433 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2434 reg &= 0xe0;
2435 reg |= src;
2436 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2437 mutex_unlock(&data->update_lock);
2438
2439 return count;
2440}
2441
2442static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002443show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2444 char *buf)
2445{
2446 struct nct6775_data *data = nct6775_update_device(dev);
2447 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2448 int index = sattr->index;
2449
2450 return show_pwm_temp_sel_common(data, buf,
2451 data->pwm_weight_temp_sel[index]);
2452}
2453
2454static ssize_t
2455store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2456 const char *buf, size_t count)
2457{
2458 struct nct6775_data *data = nct6775_update_device(dev);
2459 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2460 int nr = sattr->index;
2461 unsigned long val;
2462 int err, reg, src;
2463
2464 err = kstrtoul(buf, 10, &val);
2465 if (err < 0)
2466 return err;
2467 if (val > NUM_TEMP)
2468 return -EINVAL;
2469 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2470 !data->temp_src[val - 1]))
2471 return -EINVAL;
2472
2473 mutex_lock(&data->update_lock);
2474 if (val) {
2475 src = data->temp_src[val - 1];
2476 data->pwm_weight_temp_sel[nr] = src;
2477 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2478 reg &= 0xe0;
2479 reg |= (src | 0x80);
2480 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2481 } else {
2482 data->pwm_weight_temp_sel[nr] = 0;
2483 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2484 reg &= 0x7f;
2485 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2486 }
2487 mutex_unlock(&data->update_lock);
2488
2489 return count;
2490}
2491
2492static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002493show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2494{
2495 struct nct6775_data *data = nct6775_update_device(dev);
2496 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2497
2498 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2499}
2500
2501static ssize_t
2502store_target_temp(struct device *dev, struct device_attribute *attr,
2503 const char *buf, size_t count)
2504{
2505 struct nct6775_data *data = dev_get_drvdata(dev);
2506 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2507 int nr = sattr->index;
2508 unsigned long val;
2509 int err;
2510
2511 err = kstrtoul(buf, 10, &val);
2512 if (err < 0)
2513 return err;
2514
2515 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2516 data->target_temp_mask);
2517
2518 mutex_lock(&data->update_lock);
2519 data->target_temp[nr] = val;
2520 pwm_update_registers(data, nr);
2521 mutex_unlock(&data->update_lock);
2522 return count;
2523}
2524
2525static ssize_t
2526show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2527{
2528 struct nct6775_data *data = nct6775_update_device(dev);
2529 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2530 int nr = sattr->index;
2531
2532 return sprintf(buf, "%d\n",
2533 fan_from_reg16(data->target_speed[nr],
2534 data->fan_div[nr]));
2535}
2536
2537static ssize_t
2538store_target_speed(struct device *dev, struct device_attribute *attr,
2539 const char *buf, size_t count)
2540{
2541 struct nct6775_data *data = dev_get_drvdata(dev);
2542 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2543 int nr = sattr->index;
2544 unsigned long val;
2545 int err;
2546 u16 speed;
2547
2548 err = kstrtoul(buf, 10, &val);
2549 if (err < 0)
2550 return err;
2551
2552 val = clamp_val(val, 0, 1350000U);
2553 speed = fan_to_reg(val, data->fan_div[nr]);
2554
2555 mutex_lock(&data->update_lock);
2556 data->target_speed[nr] = speed;
2557 pwm_update_registers(data, nr);
2558 mutex_unlock(&data->update_lock);
2559 return count;
2560}
2561
2562static ssize_t
2563show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2564 char *buf)
2565{
2566 struct nct6775_data *data = nct6775_update_device(dev);
2567 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2568 int nr = sattr->nr;
2569 int index = sattr->index;
2570
2571 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2572}
2573
2574static ssize_t
2575store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2576 const char *buf, size_t count)
2577{
2578 struct nct6775_data *data = dev_get_drvdata(dev);
2579 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2580 int nr = sattr->nr;
2581 int index = sattr->index;
2582 unsigned long val;
2583 int err;
2584
2585 err = kstrtoul(buf, 10, &val);
2586 if (err < 0)
2587 return err;
2588
2589 /* Limit tolerance as needed */
2590 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2591
2592 mutex_lock(&data->update_lock);
2593 data->temp_tolerance[index][nr] = val;
2594 if (index)
2595 pwm_update_registers(data, nr);
2596 else
2597 nct6775_write_value(data,
2598 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2599 val);
2600 mutex_unlock(&data->update_lock);
2601 return count;
2602}
2603
2604/*
2605 * Fan speed tolerance is a tricky beast, since the associated register is
2606 * a tick counter, but the value is reported and configured as rpm.
2607 * Compute resulting low and high rpm values and report the difference.
2608 */
2609static ssize_t
2610show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2611 char *buf)
2612{
2613 struct nct6775_data *data = nct6775_update_device(dev);
2614 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2615 int nr = sattr->index;
2616 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2617 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2618 int tolerance;
2619
2620 if (low <= 0)
2621 low = 1;
2622 if (high > 0xffff)
2623 high = 0xffff;
2624 if (high < low)
2625 high = low;
2626
2627 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2628 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2629
2630 return sprintf(buf, "%d\n", tolerance);
2631}
2632
2633static ssize_t
2634store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2635 const char *buf, size_t count)
2636{
2637 struct nct6775_data *data = dev_get_drvdata(dev);
2638 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2639 int nr = sattr->index;
2640 unsigned long val;
2641 int err;
2642 int low, high;
2643
2644 err = kstrtoul(buf, 10, &val);
2645 if (err < 0)
2646 return err;
2647
2648 high = fan_from_reg16(data->target_speed[nr],
2649 data->fan_div[nr]) + val;
2650 low = fan_from_reg16(data->target_speed[nr],
2651 data->fan_div[nr]) - val;
2652 if (low <= 0)
2653 low = 1;
2654 if (high < low)
2655 high = low;
2656
2657 val = (fan_to_reg(low, data->fan_div[nr]) -
2658 fan_to_reg(high, data->fan_div[nr])) / 2;
2659
2660 /* Limit tolerance as needed */
2661 val = clamp_val(val, 0, data->speed_tolerance_limit);
2662
2663 mutex_lock(&data->update_lock);
2664 data->target_speed_tolerance[nr] = val;
2665 pwm_update_registers(data, nr);
2666 mutex_unlock(&data->update_lock);
2667 return count;
2668}
2669
Guenter Roeckf73cf632013-03-18 09:22:50 -07002670SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2671SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2672 store_pwm_mode, 0);
2673SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2674 store_pwm_enable, 0);
2675SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2676 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2677SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2678 show_target_temp, store_target_temp, 0);
2679SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2680 show_target_speed, store_target_speed, 0);
2681SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2682 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002683
2684/* Smart Fan registers */
2685
2686static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002687show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2688{
2689 struct nct6775_data *data = nct6775_update_device(dev);
2690 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2691 int nr = sattr->nr;
2692 int index = sattr->index;
2693
2694 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2695}
2696
2697static ssize_t
2698store_weight_temp(struct device *dev, struct device_attribute *attr,
2699 const char *buf, size_t count)
2700{
2701 struct nct6775_data *data = dev_get_drvdata(dev);
2702 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2703 int nr = sattr->nr;
2704 int index = sattr->index;
2705 unsigned long val;
2706 int err;
2707
2708 err = kstrtoul(buf, 10, &val);
2709 if (err < 0)
2710 return err;
2711
2712 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2713
2714 mutex_lock(&data->update_lock);
2715 data->weight_temp[index][nr] = val;
2716 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2717 mutex_unlock(&data->update_lock);
2718 return count;
2719}
2720
Guenter Roeckf73cf632013-03-18 09:22:50 -07002721SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2722 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2723SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2724 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2725SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2726 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2727SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2728 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2729SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2730 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2731SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2732 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002733
2734static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002735show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2736{
2737 struct nct6775_data *data = nct6775_update_device(dev);
2738 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2739 int nr = sattr->nr;
2740 int index = sattr->index;
2741
2742 return sprintf(buf, "%d\n",
2743 step_time_from_reg(data->fan_time[index][nr],
2744 data->pwm_mode[nr]));
2745}
2746
2747static ssize_t
2748store_fan_time(struct device *dev, struct device_attribute *attr,
2749 const char *buf, size_t count)
2750{
2751 struct nct6775_data *data = dev_get_drvdata(dev);
2752 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2753 int nr = sattr->nr;
2754 int index = sattr->index;
2755 unsigned long val;
2756 int err;
2757
2758 err = kstrtoul(buf, 10, &val);
2759 if (err < 0)
2760 return err;
2761
2762 val = step_time_to_reg(val, data->pwm_mode[nr]);
2763 mutex_lock(&data->update_lock);
2764 data->fan_time[index][nr] = val;
2765 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2766 mutex_unlock(&data->update_lock);
2767 return count;
2768}
2769
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002770static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002771show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2772{
2773 struct nct6775_data *data = nct6775_update_device(dev);
2774 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2775
2776 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2777}
2778
2779static ssize_t
2780store_auto_pwm(struct device *dev, struct device_attribute *attr,
2781 const char *buf, size_t count)
2782{
2783 struct nct6775_data *data = dev_get_drvdata(dev);
2784 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2785 int nr = sattr->nr;
2786 int point = sattr->index;
2787 unsigned long val;
2788 int err;
2789 u8 reg;
2790
2791 err = kstrtoul(buf, 10, &val);
2792 if (err < 0)
2793 return err;
2794 if (val > 255)
2795 return -EINVAL;
2796
2797 if (point == data->auto_pwm_num) {
2798 if (data->kind != nct6775 && !val)
2799 return -EINVAL;
2800 if (data->kind != nct6779 && val)
2801 val = 0xff;
2802 }
2803
2804 mutex_lock(&data->update_lock);
2805 data->auto_pwm[nr][point] = val;
2806 if (point < data->auto_pwm_num) {
2807 nct6775_write_value(data,
2808 NCT6775_AUTO_PWM(data, nr, point),
2809 data->auto_pwm[nr][point]);
2810 } else {
2811 switch (data->kind) {
2812 case nct6775:
2813 /* disable if needed (pwm == 0) */
2814 reg = nct6775_read_value(data,
2815 NCT6775_REG_CRITICAL_ENAB[nr]);
2816 if (val)
2817 reg |= 0x02;
2818 else
2819 reg &= ~0x02;
2820 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2821 reg);
2822 break;
2823 case nct6776:
2824 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002825 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002826 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002827 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002828 case nct6792:
Guenter Roeck6c009502012-07-01 08:23:15 -07002829 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002830 val);
2831 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002832 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002833 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002834 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002835 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002836 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002837 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002838 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002839 reg);
2840 break;
2841 }
2842 }
2843 mutex_unlock(&data->update_lock);
2844 return count;
2845}
2846
2847static ssize_t
2848show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2849{
2850 struct nct6775_data *data = nct6775_update_device(dev);
2851 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2852 int nr = sattr->nr;
2853 int point = sattr->index;
2854
2855 /*
2856 * We don't know for sure if the temperature is signed or unsigned.
2857 * Assume it is unsigned.
2858 */
2859 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2860}
2861
2862static ssize_t
2863store_auto_temp(struct device *dev, struct device_attribute *attr,
2864 const char *buf, size_t count)
2865{
2866 struct nct6775_data *data = dev_get_drvdata(dev);
2867 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2868 int nr = sattr->nr;
2869 int point = sattr->index;
2870 unsigned long val;
2871 int err;
2872
2873 err = kstrtoul(buf, 10, &val);
2874 if (err)
2875 return err;
2876 if (val > 255000)
2877 return -EINVAL;
2878
2879 mutex_lock(&data->update_lock);
2880 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2881 if (point < data->auto_pwm_num) {
2882 nct6775_write_value(data,
2883 NCT6775_AUTO_TEMP(data, nr, point),
2884 data->auto_temp[nr][point]);
2885 } else {
2886 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2887 data->auto_temp[nr][point]);
2888 }
2889 mutex_unlock(&data->update_lock);
2890 return count;
2891}
2892
Guenter Roeckf73cf632013-03-18 09:22:50 -07002893static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2894 struct attribute *attr, int index)
2895{
2896 struct device *dev = container_of(kobj, struct device, kobj);
2897 struct nct6775_data *data = dev_get_drvdata(dev);
2898 int pwm = index / 36; /* pwm index */
2899 int nr = index % 36; /* attribute index */
2900
2901 if (!(data->has_pwm & (1 << pwm)))
2902 return 0;
2903
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002904 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2905 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2906 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002907 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2908 return 0;
2909 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2910 return 0;
2911 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2912 return 0;
2913
2914 if (nr >= 22 && nr <= 35) { /* auto point */
2915 int api = (nr - 22) / 2; /* auto point index */
2916
2917 if (api > data->auto_pwm_num)
2918 return 0;
2919 }
2920 return attr->mode;
2921}
2922
2923SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2924 show_fan_time, store_fan_time, 0, 0);
2925SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2926 show_fan_time, store_fan_time, 0, 1);
2927SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2928 show_fan_time, store_fan_time, 0, 2);
2929SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2930 store_pwm, 0, 1);
2931SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2932 store_pwm, 0, 2);
2933SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2934 show_temp_tolerance, store_temp_tolerance, 0, 0);
2935SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2936 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2937 0, 1);
2938
2939SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2940 0, 3);
2941
2942SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2943 store_pwm, 0, 4);
2944
2945SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2946 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2947SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2948 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2949
2950SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2951 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2952SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2953 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2954
2955SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2956 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2957SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2958 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2959
2960SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2961 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2962SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2963 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2964
2965SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2966 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2967SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2968 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2969
2970SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2971 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2972SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2973 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2974
2975SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2976 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2977SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2978 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2979
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002980/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002981 * nct6775_pwm_is_visible uses the index into the following array
2982 * to determine if attributes should be created or not.
2983 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002984 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002985static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2986 &sensor_dev_template_pwm,
2987 &sensor_dev_template_pwm_mode,
2988 &sensor_dev_template_pwm_enable,
2989 &sensor_dev_template_pwm_temp_sel,
2990 &sensor_dev_template_pwm_temp_tolerance,
2991 &sensor_dev_template_pwm_crit_temp_tolerance,
2992 &sensor_dev_template_pwm_target_temp,
2993 &sensor_dev_template_fan_target,
2994 &sensor_dev_template_fan_tolerance,
2995 &sensor_dev_template_pwm_stop_time,
2996 &sensor_dev_template_pwm_step_up_time,
2997 &sensor_dev_template_pwm_step_down_time,
2998 &sensor_dev_template_pwm_start,
2999 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003000 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003001 &sensor_dev_template_pwm_weight_temp_step,
3002 &sensor_dev_template_pwm_weight_temp_step_tol,
3003 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003004 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003005 &sensor_dev_template_pwm_max, /* 19 */
3006 &sensor_dev_template_pwm_step, /* 20 */
3007 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3008 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3009 &sensor_dev_template_pwm_auto_point1_temp,
3010 &sensor_dev_template_pwm_auto_point2_pwm,
3011 &sensor_dev_template_pwm_auto_point2_temp,
3012 &sensor_dev_template_pwm_auto_point3_pwm,
3013 &sensor_dev_template_pwm_auto_point3_temp,
3014 &sensor_dev_template_pwm_auto_point4_pwm,
3015 &sensor_dev_template_pwm_auto_point4_temp,
3016 &sensor_dev_template_pwm_auto_point5_pwm,
3017 &sensor_dev_template_pwm_auto_point5_temp,
3018 &sensor_dev_template_pwm_auto_point6_pwm,
3019 &sensor_dev_template_pwm_auto_point6_temp,
3020 &sensor_dev_template_pwm_auto_point7_pwm,
3021 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003022
Guenter Roeckf73cf632013-03-18 09:22:50 -07003023 NULL
3024};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003025
Guenter Roeckf73cf632013-03-18 09:22:50 -07003026static struct sensor_template_group nct6775_pwm_template_group = {
3027 .templates = nct6775_attributes_pwm_template,
3028 .is_visible = nct6775_pwm_is_visible,
3029 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003030};
3031
3032static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003033show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3034{
3035 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003036
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003037 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3038}
3039
3040static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3041
Guenter Roecka6bd5872012-12-04 03:13:34 -08003042/* Case open detection */
3043
3044static ssize_t
3045clear_caseopen(struct device *dev, struct device_attribute *attr,
3046 const char *buf, size_t count)
3047{
3048 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003049 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3050 unsigned long val;
3051 u8 reg;
3052 int ret;
3053
3054 if (kstrtoul(buf, 10, &val) || val != 0)
3055 return -EINVAL;
3056
3057 mutex_lock(&data->update_lock);
3058
3059 /*
3060 * Use CR registers to clear caseopen status.
3061 * The CR registers are the same for all chips, and not all chips
3062 * support clearing the caseopen status through "regular" registers.
3063 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003064 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003065 if (ret) {
3066 count = ret;
3067 goto error;
3068 }
3069
Guenter Roeckdf612d52013-07-08 13:15:04 -07003070 superio_select(data->sioreg, NCT6775_LD_ACPI);
3071 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003072 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003073 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003074 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003075 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3076 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003077
3078 data->valid = false; /* Force cache refresh */
3079error:
3080 mutex_unlock(&data->update_lock);
3081 return count;
3082}
3083
Guenter Roeckf73cf632013-03-18 09:22:50 -07003084static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3085 clear_caseopen, INTRUSION_ALARM_BASE);
3086static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3087 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003088static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3089 store_beep, INTRUSION_ALARM_BASE);
3090static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3091 store_beep, INTRUSION_ALARM_BASE + 1);
3092static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3093 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003094
3095static umode_t nct6775_other_is_visible(struct kobject *kobj,
3096 struct attribute *attr, int index)
3097{
3098 struct device *dev = container_of(kobj, struct device, kobj);
3099 struct nct6775_data *data = dev_get_drvdata(dev);
3100
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003101 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003102 return 0;
3103
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003104 if (index == 1 || index == 2) {
3105 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003106 return 0;
3107 }
3108
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003109 if (index == 3 || index == 4) {
3110 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003111 return 0;
3112 }
3113
Guenter Roeckf73cf632013-03-18 09:22:50 -07003114 return attr->mode;
3115}
3116
3117/*
3118 * nct6775_other_is_visible uses the index into the following array
3119 * to determine if attributes should be created or not.
3120 * Any change in order or content must be matched.
3121 */
3122static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003123 &dev_attr_cpu0_vid.attr, /* 0 */
3124 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3125 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3126 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3127 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3128 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003129
3130 NULL
3131};
3132
3133static const struct attribute_group nct6775_group_other = {
3134 .attrs = nct6775_attributes_other,
3135 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003136};
3137
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003138static inline void nct6775_init_device(struct nct6775_data *data)
3139{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003140 int i;
3141 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003142
3143 /* Start monitoring if needed */
3144 if (data->REG_CONFIG) {
3145 tmp = nct6775_read_value(data, data->REG_CONFIG);
3146 if (!(tmp & 0x01))
3147 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3148 }
3149
Guenter Roeckaa136e52012-12-04 03:26:05 -08003150 /* Enable temperature sensors if needed */
3151 for (i = 0; i < NUM_TEMP; i++) {
3152 if (!(data->have_temp & (1 << i)))
3153 continue;
3154 if (!data->reg_temp_config[i])
3155 continue;
3156 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3157 if (tmp & 0x01)
3158 nct6775_write_value(data, data->reg_temp_config[i],
3159 tmp & 0xfe);
3160 }
3161
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003162 /* Enable VBAT monitoring if needed */
3163 tmp = nct6775_read_value(data, data->REG_VBAT);
3164 if (!(tmp & 0x01))
3165 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003166
3167 diode = nct6775_read_value(data, data->REG_DIODE);
3168
3169 for (i = 0; i < data->temp_fixed_num; i++) {
3170 if (!(data->have_temp_fixed & (1 << i)))
3171 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003172 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3173 data->temp_type[i]
3174 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003175 else /* thermistor */
3176 data->temp_type[i] = 4;
3177 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003178}
3179
Guenter Roeckf73cf632013-03-18 09:22:50 -07003180static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003181nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003182{
David Bartley578ab5f2013-06-24 22:28:28 -07003183 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3184 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003185 int sioreg = data->sioreg;
3186 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003187
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003188 /* Store SIO_REG_ENABLE for use during resume */
3189 superio_select(sioreg, NCT6775_LD_HWM);
3190 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3191
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003192 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3193 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003194 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003195
3196 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003197 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003198
3199 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003200 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003201 fan4min = false;
3202 fan5pin = false;
3203 fan6pin = false;
3204 pwm4pin = false;
3205 pwm5pin = false;
3206 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003207 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003208 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003209 const char *board_vendor, *board_name;
3210
3211 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3212 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3213
3214 if (board_name && board_vendor &&
3215 !strcmp(board_vendor, "ASRock")) {
3216 /*
3217 * Auxiliary fan monitoring is not enabled on ASRock
3218 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3219 * Observed with BIOS version 2.00.
3220 */
3221 if (!strcmp(board_name, "Z77 Pro4-M")) {
3222 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3223 data->sio_reg_enable |= 0xe0;
3224 superio_outb(sioreg, SIO_REG_ENABLE,
3225 data->sio_reg_enable);
3226 }
3227 }
3228 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003229
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003230 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003231 fan3pin = gpok;
3232 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003233 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003234
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003235 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003236 fan4pin = gpok;
3237 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003238 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003239
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003240 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003241 fan5pin = gpok;
3242 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003243 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003244
3245 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003246 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003247 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003248 pwm4pin = false;
3249 pwm5pin = false;
3250 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003251 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003252 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003253 fan3pin = !(regval & 0x80);
3254 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003255
3256 fan4pin = false;
3257 fan4min = false;
3258 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003259 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003260 pwm4pin = false;
3261 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003262 pwm6pin = false;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003263 } else { /* NCT6779D, NCT6791D, or NCT6792D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003264 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003265
3266 fan3pin = !(regval & (1 << 5));
3267 fan4pin = !(regval & (1 << 6));
3268 fan5pin = !(regval & (1 << 7));
3269
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003270 pwm3pin = !(regval & (1 << 0));
3271 pwm4pin = !(regval & (1 << 1));
3272 pwm5pin = !(regval & (1 << 2));
3273
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003274 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003275
Guenter Roeck8aefb932014-11-16 09:50:04 -08003276 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003277 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003278 fan6pin = (regval & (1 << 1));
3279 pwm6pin = (regval & (1 << 0));
3280 } else { /* NCT6779D */
3281 fan6pin = false;
3282 pwm6pin = false;
3283 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003284 }
3285
David Bartley578ab5f2013-06-24 22:28:28 -07003286 /* fan 1 and 2 (0x03) are always present */
3287 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3288 (fan5pin << 4) | (fan6pin << 5);
3289 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3290 (fan5pin << 4);
3291 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3292 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003293}
3294
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003295static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3296 int *available, int *mask)
3297{
3298 int i;
3299 u8 src;
3300
3301 for (i = 0; i < data->pwm_num && *available; i++) {
3302 int index;
3303
3304 if (!regp[i])
3305 continue;
3306 src = nct6775_read_value(data, regp[i]);
3307 src &= 0x1f;
3308 if (!src || (*mask & (1 << src)))
3309 continue;
3310 if (src >= data->temp_label_num ||
3311 !strlen(data->temp_label[src]))
3312 continue;
3313
3314 index = __ffs(*available);
3315 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3316 *available &= ~(1 << index);
3317 *mask |= 1 << src;
3318 }
3319}
3320
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003321static int nct6775_probe(struct platform_device *pdev)
3322{
3323 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003324 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003325 struct nct6775_data *data;
3326 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003327 int i, s, err = 0;
3328 int src, mask, available;
3329 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003330 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003331 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003332 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003333 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003334 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003335 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003336 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003337
3338 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3339 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3340 DRVNAME))
3341 return -EBUSY;
3342
3343 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3344 GFP_KERNEL);
3345 if (!data)
3346 return -ENOMEM;
3347
3348 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003349 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003350 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003351 mutex_init(&data->update_lock);
3352 data->name = nct6775_device_names[data->kind];
3353 data->bank = 0xff; /* Force initial bank selection */
3354 platform_set_drvdata(pdev, data);
3355
3356 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003357 case nct6106:
3358 data->in_num = 9;
3359 data->pwm_num = 3;
3360 data->auto_pwm_num = 4;
3361 data->temp_fixed_num = 3;
3362 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003363 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003364
3365 data->fan_from_reg = fan_from_reg13;
3366 data->fan_from_reg_min = fan_from_reg13;
3367
3368 data->temp_label = nct6776_temp_label;
3369 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3370
3371 data->REG_VBAT = NCT6106_REG_VBAT;
3372 data->REG_DIODE = NCT6106_REG_DIODE;
3373 data->DIODE_MASK = NCT6106_DIODE_MASK;
3374 data->REG_VIN = NCT6106_REG_IN;
3375 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3376 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3377 data->REG_TARGET = NCT6106_REG_TARGET;
3378 data->REG_FAN = NCT6106_REG_FAN;
3379 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3380 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3381 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3382 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3383 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3384 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3385 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3386 data->REG_PWM[0] = NCT6106_REG_PWM;
3387 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3388 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3389 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3390 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3391 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3392 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3393 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3394 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3395 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3396 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3397 data->REG_CRITICAL_TEMP_TOLERANCE
3398 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3399 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3400 data->CRITICAL_PWM_ENABLE_MASK
3401 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3402 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3403 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3404 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3405 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3406 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3407 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3408 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3409 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3410 data->REG_ALARM = NCT6106_REG_ALARM;
3411 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003412 data->REG_BEEP = NCT6106_REG_BEEP;
3413 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003414
3415 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003416 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003417 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003418 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003419 reg_temp_over = NCT6106_REG_TEMP_OVER;
3420 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3421 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3422 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3423 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003424 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3425 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003426
3427 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003428 case nct6775:
3429 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003430 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003431 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003432 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003433 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003434 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003435 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003436
3437 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003438 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003439
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003440 data->fan_from_reg = fan_from_reg16;
3441 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003442 data->target_temp_mask = 0x7f;
3443 data->tolerance_mask = 0x0f;
3444 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003445
Guenter Roeckaa136e52012-12-04 03:26:05 -08003446 data->temp_label = nct6775_temp_label;
3447 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3448
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003449 data->REG_CONFIG = NCT6775_REG_CONFIG;
3450 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003451 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003452 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003453 data->REG_VIN = NCT6775_REG_IN;
3454 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3455 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003456 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003457 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003458 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003459 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003460 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003461 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003462 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3463 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3464 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003465 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003466 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3467 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3468 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3469 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003470 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003471 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3472 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3473 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003474 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3475 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3476 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3477 data->REG_CRITICAL_TEMP_TOLERANCE
3478 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003479 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3480 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003481 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003482 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3483 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3484 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3485 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003486 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003487 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003488
3489 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003490 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003491 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003492 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003493 reg_temp_over = NCT6775_REG_TEMP_OVER;
3494 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3495 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3496 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3497 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3498
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003499 break;
3500 case nct6776:
3501 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003502 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003503 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003504 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003505 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003506 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003507 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003508
3509 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003510 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003511
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003512 data->fan_from_reg = fan_from_reg13;
3513 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003514 data->target_temp_mask = 0xff;
3515 data->tolerance_mask = 0x07;
3516 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003517
Guenter Roeckaa136e52012-12-04 03:26:05 -08003518 data->temp_label = nct6776_temp_label;
3519 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3520
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003521 data->REG_CONFIG = NCT6775_REG_CONFIG;
3522 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003523 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003524 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003525 data->REG_VIN = NCT6775_REG_IN;
3526 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3527 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003528 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003529 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003530 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003532 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003533 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003534 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003535 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3536 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003537 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003538 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003539 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3540 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003541 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3542 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003543 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3544 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3545 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003546 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3547 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3548 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3549 data->REG_CRITICAL_TEMP_TOLERANCE
3550 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003551 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3552 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003553 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003554 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3555 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3556 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3557 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003558 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003559 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003560
3561 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003562 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003563 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003564 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003565 reg_temp_over = NCT6775_REG_TEMP_OVER;
3566 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3567 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3568 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3569 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3570
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003571 break;
3572 case nct6779:
3573 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003574 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003575 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003576 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003577 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003578 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003579 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003580
3581 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003582 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003583
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003584 data->fan_from_reg = fan_from_reg13;
3585 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003586 data->target_temp_mask = 0xff;
3587 data->tolerance_mask = 0x07;
3588 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003589
Guenter Roeckaa136e52012-12-04 03:26:05 -08003590 data->temp_label = nct6779_temp_label;
3591 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3592
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003593 data->REG_CONFIG = NCT6775_REG_CONFIG;
3594 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003595 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003596 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003597 data->REG_VIN = NCT6779_REG_IN;
3598 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3599 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003600 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003601 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003602 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003603 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003604 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003605 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003606 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003607 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3608 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003609 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003610 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003611 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3612 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003613 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3614 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003615 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3616 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3617 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003618 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3619 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3620 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3621 data->REG_CRITICAL_TEMP_TOLERANCE
3622 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003623 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3624 data->CRITICAL_PWM_ENABLE_MASK
3625 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3626 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003627 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3628 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003629 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003630 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3631 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3632 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3633 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003634 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003635 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003636
3637 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003638 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003639 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003640 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003641 reg_temp_over = NCT6779_REG_TEMP_OVER;
3642 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3643 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3644 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3645 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3646
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003647 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003648 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003649 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003650 data->in_num = 15;
3651 data->pwm_num = 6;
3652 data->auto_pwm_num = 4;
3653 data->has_fan_div = false;
3654 data->temp_fixed_num = 6;
3655 data->num_temp_alarms = 2;
3656 data->num_temp_beeps = 2;
3657
3658 data->ALARM_BITS = NCT6791_ALARM_BITS;
3659 data->BEEP_BITS = NCT6779_BEEP_BITS;
3660
3661 data->fan_from_reg = fan_from_reg13;
3662 data->fan_from_reg_min = fan_from_reg13;
3663 data->target_temp_mask = 0xff;
3664 data->tolerance_mask = 0x07;
3665 data->speed_tolerance_limit = 63;
3666
3667 data->temp_label = nct6779_temp_label;
3668 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3669
3670 data->REG_CONFIG = NCT6775_REG_CONFIG;
3671 data->REG_VBAT = NCT6775_REG_VBAT;
3672 data->REG_DIODE = NCT6775_REG_DIODE;
3673 data->DIODE_MASK = NCT6775_DIODE_MASK;
3674 data->REG_VIN = NCT6779_REG_IN;
3675 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3676 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3677 data->REG_TARGET = NCT6775_REG_TARGET;
3678 data->REG_FAN = NCT6779_REG_FAN;
3679 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3680 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3681 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3682 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3683 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003684 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3685 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003686 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3687 data->REG_PWM[0] = NCT6775_REG_PWM;
3688 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3689 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003690 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3691 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003692 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3693 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3694 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3695 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3696 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3697 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3698 data->REG_CRITICAL_TEMP_TOLERANCE
3699 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3700 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3701 data->CRITICAL_PWM_ENABLE_MASK
3702 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3703 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3704 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3705 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3706 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003707 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3708 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3709 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3710 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003711 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003712 if (data->kind == nct6791)
3713 data->REG_BEEP = NCT6776_REG_BEEP;
3714 else
3715 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003716
3717 reg_temp = NCT6779_REG_TEMP;
3718 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003719 if (data->kind == nct6791) {
3720 reg_temp_mon = NCT6779_REG_TEMP_MON;
3721 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3722 } else {
3723 reg_temp_mon = NCT6792_REG_TEMP_MON;
3724 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3725 }
David Bartley578ab5f2013-06-24 22:28:28 -07003726 reg_temp_over = NCT6779_REG_TEMP_OVER;
3727 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3728 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3729 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3730 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3731
3732 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003733 default:
3734 return -ENODEV;
3735 }
3736 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003737 data->have_temp = 0;
3738
3739 /*
3740 * On some boards, not all available temperature sources are monitored,
3741 * even though some of the monitoring registers are unused.
3742 * Get list of unused monitoring registers, then detect if any fan
3743 * controls are configured to use unmonitored temperature sources.
3744 * If so, assign the unmonitored temperature sources to available
3745 * monitoring registers.
3746 */
3747 mask = 0;
3748 available = 0;
3749 for (i = 0; i < num_reg_temp; i++) {
3750 if (reg_temp[i] == 0)
3751 continue;
3752
3753 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3754 if (!src || (mask & (1 << src)))
3755 available |= 1 << i;
3756
3757 mask |= 1 << src;
3758 }
3759
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003760 /*
3761 * Now find unmonitored temperature registers and enable monitoring
3762 * if additional monitoring registers are available.
3763 */
3764 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3765 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3766
Guenter Roeckaa136e52012-12-04 03:26:05 -08003767 mask = 0;
3768 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3769 for (i = 0; i < num_reg_temp; i++) {
3770 if (reg_temp[i] == 0)
3771 continue;
3772
3773 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3774 if (!src || (mask & (1 << src)))
3775 continue;
3776
3777 if (src >= data->temp_label_num ||
3778 !strlen(data->temp_label[src])) {
3779 dev_info(dev,
3780 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3781 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3782 continue;
3783 }
3784
3785 mask |= 1 << src;
3786
3787 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3788 if (src <= data->temp_fixed_num) {
3789 data->have_temp |= 1 << (src - 1);
3790 data->have_temp_fixed |= 1 << (src - 1);
3791 data->reg_temp[0][src - 1] = reg_temp[i];
3792 data->reg_temp[1][src - 1] = reg_temp_over[i];
3793 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003794 if (reg_temp_crit_h && reg_temp_crit_h[i])
3795 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3796 else if (reg_temp_crit[src - 1])
3797 data->reg_temp[3][src - 1]
3798 = reg_temp_crit[src - 1];
3799 if (reg_temp_crit_l && reg_temp_crit_l[i])
3800 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003801 data->reg_temp_config[src - 1] = reg_temp_config[i];
3802 data->temp_src[src - 1] = src;
3803 continue;
3804 }
3805
3806 if (s >= NUM_TEMP)
3807 continue;
3808
3809 /* Use dynamic index for other sources */
3810 data->have_temp |= 1 << s;
3811 data->reg_temp[0][s] = reg_temp[i];
3812 data->reg_temp[1][s] = reg_temp_over[i];
3813 data->reg_temp[2][s] = reg_temp_hyst[i];
3814 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003815 if (reg_temp_crit_h && reg_temp_crit_h[i])
3816 data->reg_temp[3][s] = reg_temp_crit_h[i];
3817 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003818 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003819 if (reg_temp_crit_l && reg_temp_crit_l[i])
3820 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003821
3822 data->temp_src[s] = src;
3823 s++;
3824 }
3825
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003826 /*
3827 * Repeat with temperatures used for fan control.
3828 * This set of registers does not support limits.
3829 */
3830 for (i = 0; i < num_reg_temp_mon; i++) {
3831 if (reg_temp_mon[i] == 0)
3832 continue;
3833
3834 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3835 if (!src || (mask & (1 << src)))
3836 continue;
3837
3838 if (src >= data->temp_label_num ||
3839 !strlen(data->temp_label[src])) {
3840 dev_info(dev,
3841 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3842 src, i, data->REG_TEMP_SEL[i],
3843 reg_temp_mon[i]);
3844 continue;
3845 }
3846
3847 mask |= 1 << src;
3848
3849 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3850 if (src <= data->temp_fixed_num) {
3851 if (data->have_temp & (1 << (src - 1)))
3852 continue;
3853 data->have_temp |= 1 << (src - 1);
3854 data->have_temp_fixed |= 1 << (src - 1);
3855 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3856 data->temp_src[src - 1] = src;
3857 continue;
3858 }
3859
3860 if (s >= NUM_TEMP)
3861 continue;
3862
3863 /* Use dynamic index for other sources */
3864 data->have_temp |= 1 << s;
3865 data->reg_temp[0][s] = reg_temp_mon[i];
3866 data->temp_src[s] = src;
3867 s++;
3868 }
3869
Guenter Roeckaa136e52012-12-04 03:26:05 -08003870#ifdef USE_ALTERNATE
3871 /*
3872 * Go through the list of alternate temp registers and enable
3873 * if possible.
3874 * The temperature is already monitored if the respective bit in <mask>
3875 * is set.
3876 */
3877 for (i = 0; i < data->temp_label_num - 1; i++) {
3878 if (!reg_temp_alternate[i])
3879 continue;
3880 if (mask & (1 << (i + 1)))
3881 continue;
3882 if (i < data->temp_fixed_num) {
3883 if (data->have_temp & (1 << i))
3884 continue;
3885 data->have_temp |= 1 << i;
3886 data->have_temp_fixed |= 1 << i;
3887 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003888 if (i < num_reg_temp) {
3889 data->reg_temp[1][i] = reg_temp_over[i];
3890 data->reg_temp[2][i] = reg_temp_hyst[i];
3891 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003892 data->temp_src[i] = i + 1;
3893 continue;
3894 }
3895
3896 if (s >= NUM_TEMP) /* Abort if no more space */
3897 break;
3898
3899 data->have_temp |= 1 << s;
3900 data->reg_temp[0][s] = reg_temp_alternate[i];
3901 data->temp_src[s] = i + 1;
3902 s++;
3903 }
3904#endif /* USE_ALTERNATE */
3905
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003906 /* Initialize the chip */
3907 nct6775_init_device(data);
3908
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003909 err = superio_enter(sio_data->sioreg);
3910 if (err)
3911 return err;
3912
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003913 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3914 switch (data->kind) {
3915 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003916 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003917 break;
3918 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003919 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003920 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003921 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003922 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003923 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003924 case nct6792:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003925 break;
3926 }
3927
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003928 /*
3929 * Read VID value
3930 * We can get the VID input values directly at logical device D 0xe3.
3931 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003932 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003933 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3934 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3935 data->vrm = vid_which_vrm();
3936 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003937
3938 if (fan_debounce) {
3939 u8 tmp;
3940
3941 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3942 tmp = superio_inb(sio_data->sioreg,
3943 NCT6775_REG_CR_FAN_DEBOUNCE);
3944 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003945 case nct6106:
3946 tmp |= 0xe0;
3947 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003948 case nct6775:
3949 tmp |= 0x1e;
3950 break;
3951 case nct6776:
3952 case nct6779:
3953 tmp |= 0x3e;
3954 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003955 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003956 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003957 tmp |= 0x7e;
3958 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003959 }
3960 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3961 tmp);
3962 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3963 data->name);
3964 }
3965
Guenter Roeckdf612d52013-07-08 13:15:04 -07003966 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003967
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003968 superio_exit(sio_data->sioreg);
3969
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003970 /* Read fan clock dividers immediately */
3971 nct6775_init_fan_common(dev, data);
3972
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003973 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003974 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3975 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003976 if (IS_ERR(group))
3977 return PTR_ERR(group);
3978
Axel Lin55bdee62014-07-24 08:59:34 +08003979 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003980
Guenter Roeckf73cf632013-03-18 09:22:50 -07003981 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3982 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003983 if (IS_ERR(group))
3984 return PTR_ERR(group);
3985
Axel Lin55bdee62014-07-24 08:59:34 +08003986 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003987
Guenter Roeckf73cf632013-03-18 09:22:50 -07003988 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3989 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003990 if (IS_ERR(group))
3991 return PTR_ERR(group);
3992
Axel Lin55bdee62014-07-24 08:59:34 +08003993 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003994
Guenter Roeckf73cf632013-03-18 09:22:50 -07003995 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3996 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003997 if (IS_ERR(group))
3998 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003999
Axel Lin55bdee62014-07-24 08:59:34 +08004000 data->groups[num_attr_groups++] = group;
4001 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004002
Guenter Roecka150d952013-07-11 22:55:22 -07004003 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4004 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004005 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004006}
4007
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004008static void nct6791_enable_io_mapping(int sioaddr)
4009{
4010 int val;
4011
4012 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4013 if (val & 0x10) {
4014 pr_info("Enabling hardware monitor logical device mappings.\n");
4015 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4016 val & ~0x10);
4017 }
4018}
4019
Guenter Roeck48e93182015-02-07 08:48:49 -08004020static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004021{
4022 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004023
4024 mutex_lock(&data->update_lock);
4025 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004026 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004027 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4028 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4029 }
4030 mutex_unlock(&data->update_lock);
4031
4032 return 0;
4033}
4034
Guenter Roeck48e93182015-02-07 08:48:49 -08004035static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004036{
4037 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004038 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004039 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004040 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004041
4042 mutex_lock(&data->update_lock);
4043 data->bank = 0xff; /* Force initial bank selection */
4044
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004045 err = superio_enter(sioreg);
4046 if (err)
4047 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004048
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004049 superio_select(sioreg, NCT6775_LD_HWM);
4050 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4051 if (reg != data->sio_reg_enable)
4052 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4053
4054 if (data->kind == nct6791 || data->kind == nct6792)
4055 nct6791_enable_io_mapping(sioreg);
4056
4057 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004058
Guenter Roeck84d19d92012-12-04 08:01:39 -08004059 /* Restore limits */
4060 for (i = 0; i < data->in_num; i++) {
4061 if (!(data->have_in & (1 << i)))
4062 continue;
4063
4064 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4065 data->in[i][1]);
4066 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4067 data->in[i][2]);
4068 }
4069
Guenter Roeckc409fd42013-04-09 05:04:00 -07004070 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004071 if (!(data->has_fan_min & (1 << i)))
4072 continue;
4073
4074 nct6775_write_value(data, data->REG_FAN_MIN[i],
4075 data->fan_min[i]);
4076 }
4077
4078 for (i = 0; i < NUM_TEMP; i++) {
4079 if (!(data->have_temp & (1 << i)))
4080 continue;
4081
Guenter Roeckc409fd42013-04-09 05:04:00 -07004082 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004083 if (data->reg_temp[j][i])
4084 nct6775_write_temp(data, data->reg_temp[j][i],
4085 data->temp[j][i]);
4086 }
4087
4088 /* Restore other settings */
4089 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004090 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004091 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4092 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4093 }
4094
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004095abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004096 /* Force re-reading all values */
4097 data->valid = false;
4098 mutex_unlock(&data->update_lock);
4099
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004100 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004101}
4102
Guenter Roeck48e93182015-02-07 08:48:49 -08004103static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004104
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004105static struct platform_driver nct6775_driver = {
4106 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004107 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004108 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004109 },
4110 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004111};
4112
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004113static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004114 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004115 "NCT6775F",
4116 "NCT6776D/F",
4117 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004118 "NCT6791D",
Guenter Roeck8aefb932014-11-16 09:50:04 -08004119 "NCT6792D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004120};
4121
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004122/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004123static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004124{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004125 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004126 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004127 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004128
4129 err = superio_enter(sioaddr);
4130 if (err)
4131 return err;
4132
4133 if (force_id)
4134 val = force_id;
4135 else
4136 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4137 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4138 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004139 case SIO_NCT6106_ID:
4140 sio_data->kind = nct6106;
4141 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004142 case SIO_NCT6775_ID:
4143 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004144 break;
4145 case SIO_NCT6776_ID:
4146 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004147 break;
4148 case SIO_NCT6779_ID:
4149 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004150 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004151 case SIO_NCT6791_ID:
4152 sio_data->kind = nct6791;
4153 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004154 case SIO_NCT6792_ID:
4155 sio_data->kind = nct6792;
4156 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004157 default:
4158 if (val != 0xffff)
4159 pr_debug("unsupported chip ID: 0x%04x\n", val);
4160 superio_exit(sioaddr);
4161 return -ENODEV;
4162 }
4163
4164 /* We have a known chip, find the HWM I/O address */
4165 superio_select(sioaddr, NCT6775_LD_HWM);
4166 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4167 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004168 addr = val & IOREGION_ALIGNMENT;
4169 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004170 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4171 superio_exit(sioaddr);
4172 return -ENODEV;
4173 }
4174
4175 /* Activate logical device if needed */
4176 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4177 if (!(val & 0x01)) {
4178 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4179 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4180 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004181
Guenter Roeck8aefb932014-11-16 09:50:04 -08004182 if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004183 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004184
4185 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004186 pr_info("Found %s or compatible chip at %#x:%#x\n",
4187 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004188 sio_data->sioreg = sioaddr;
4189
Guenter Roeck698a7c22013-04-05 07:35:25 -07004190 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004191}
4192
4193/*
4194 * when Super-I/O functions move to a separate file, the Super-I/O
4195 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004196 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004197 * must keep track of the device
4198 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004199static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004200
4201static int __init sensors_nct6775_init(void)
4202{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004203 int i, err;
4204 bool found = false;
4205 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004206 struct resource res;
4207 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004208 int sioaddr[2] = { 0x2e, 0x4e };
4209
4210 err = platform_driver_register(&nct6775_driver);
4211 if (err)
4212 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004213
4214 /*
4215 * initialize sio_data->kind and sio_data->sioreg.
4216 *
4217 * when Super-I/O functions move to a separate file, the Super-I/O
4218 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4219 * nct6775 hardware monitor, and call probe()
4220 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004221 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4222 address = nct6775_find(sioaddr[i], &sio_data);
4223 if (address <= 0)
4224 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004225
Guenter Roeck698a7c22013-04-05 07:35:25 -07004226 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004227
Guenter Roeck698a7c22013-04-05 07:35:25 -07004228 pdev[i] = platform_device_alloc(DRVNAME, address);
4229 if (!pdev[i]) {
4230 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004231 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004232 }
4233
4234 err = platform_device_add_data(pdev[i], &sio_data,
4235 sizeof(struct nct6775_sio_data));
4236 if (err)
4237 goto exit_device_put;
4238
4239 memset(&res, 0, sizeof(res));
4240 res.name = DRVNAME;
4241 res.start = address + IOREGION_OFFSET;
4242 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4243 res.flags = IORESOURCE_IO;
4244
4245 err = acpi_check_resource_conflict(&res);
4246 if (err) {
4247 platform_device_put(pdev[i]);
4248 pdev[i] = NULL;
4249 continue;
4250 }
4251
4252 err = platform_device_add_resources(pdev[i], &res, 1);
4253 if (err)
4254 goto exit_device_put;
4255
4256 /* platform_device_add calls probe() */
4257 err = platform_device_add(pdev[i]);
4258 if (err)
4259 goto exit_device_put;
4260 }
4261 if (!found) {
4262 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004263 goto exit_unregister;
4264 }
4265
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004266 return 0;
4267
4268exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004269 platform_device_put(pdev[i]);
4270exit_device_unregister:
4271 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004272 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004273 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004274 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004275exit_unregister:
4276 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004277 return err;
4278}
4279
4280static void __exit sensors_nct6775_exit(void)
4281{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004282 int i;
4283
4284 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4285 if (pdev[i])
4286 platform_device_unregister(pdev[i]);
4287 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004288 platform_driver_unregister(&nct6775_driver);
4289}
4290
4291MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeck8aefb932014-11-16 09:50:04 -08004292MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004293MODULE_LICENSE("GPL");
4294
4295module_init(sensors_nct6775_init);
4296module_exit(sensors_nct6775_exit);